打印机会出现mysql更改表字符集一个字符

单元5 文字排版与打印_百度文库
两大类热门资源免费畅读
续费一年阅读会员,立省24元!
单元5 文字排版与打印
上传于||暂无简介
阅读已结束,如果下载本文需要使用0下载券
想免费下载更多文档?
下载文档到电脑,查找使用更方便
还剩21页未读,继续阅读
你可能喜欢谁打印了这个字符串 - 为程序员服务
谁打印了这个字符串
前段时间在调试时遇到一个问题,运行程序出现错误,但并没有足够的信息来定位错误所在。可喜的是控制台上输出了一些可疑信息,只要找到了哪里打印了这些信息便有可能推断错误的原因。然而由于程序过于庞大,不可能一步一步跟踪调试去查找哪条语句执行后输出了这段字符串。尝试在所有的代码中搜索这段字符串也无功而返。后来突发奇想,能否在输出字符串时设置一个条件断点,只要输出的这段信息就中断,这样就可以在中断后找到何处打印了这些可疑信息,进而解决程序的问题了。
经过大量的搜索之后,在Stack Overflow上找到了
,并且成功的解决了我的问题。被采用答案的作者
Anthony Arnold
由于十分喜欢这个问题,所以写了一篇关于它的
。我也特别喜欢这个问题,之前遇到过多次,但都采用别的方式解决,而只有这个答案最完美。同时它综合运用了很多知识,能够给我们的调试带来不少启发。因为网上也没有再找到其它的解决方案,所以我决定翻译此文,后面对原文再进行其它平台的补充。离开学校之后第一次翻译,不好之处欢迎指正。
调试STDOUT
前几天我遇到一个很有趣的
,提问者希望
能够在一个特定的字符串写到stdout时中断程序。
除非你至少掌握了一些下面的知识,否则并不容易得到这个问题的答案:
C语言标准库
我想出了一种可行的但是不可移植的解决方案,它依赖于x86指令集和Linux的系统调用
,所以本文的讨论限制在特定操作系统内核上的特定架构。
我们使用下面的代码(定义在hello.c中)来演示如何用GDB在
"Hello World!\n"
写入stdout时中断。(feihu注:代码作了一定的修改,增加了另外一个输出字符串的函数,以更好的演示捕获特定字符串)
#include &stdio.h&
void test()
printf("Test\n");
int main()
printf("Hello World!\n");
用下面的命令编译链接:
# gcc -g -o hello hello.c
用下面的命令调试:
# gdb hello
在write中设置断点
第一步,我们需要找出如何在有数据被写到stdout时中断程序。我们假设你调试代码的作者没有疯,他们采用了所选语言的标准用法来向stdout写数据(比如C语言中的
),或者他们直接调用系统调用
也调用的是
,所以不管采用上面哪种方式都可以。
因此你可以在
系统调用中设置一个断点:
$gdb break write
GDB也许会抱怨它并不知道
函数,但是它可以在将来这个函数有效时再在其中设置这一断点:
Function "write" not defined.
Make breakpoint pending on future shared library load? (y or [n])
这完全没问题,直接输入
在write中写到STDOUT时设置断点
一旦你能够在
函数中设置断点后,你需要设置一个条件,只有在写到stdout时才中断,这里有一点复杂。看看
:第一个参数
是要写的文件描述符,在Linux中,stdout的文件描述符是
(也许你使用的平台有所不同)。
于是你的第一反应是这样:
$gdb condition 1 fd == 1
但是很遗憾,这不起作用。
(feihu注:会出现这样的错误
No symbol "fd" in current context.
)除非你非常幸运,否则不可能已经加载了
系统调用的调试
,这意味着你不能以参数名来访问传给系统调用的参数。
获取系统调用参数
当然,还有其它的方法可以获取传给系统调用的参数,GDB提供了非常完善的手段让你来访问各种汇编寄存器,在这个问题中,我们感兴趣的是
寄存器。(feihu注:这里仅适用于x86 32位系统,x86 64位系统的解决方案请向下看。)
当一个函数调用发生时,栈中储存了:
函数的返回地址
指向函数参数的指针
这意味着当调用
函数时,栈的结构可能像下面一样:
这是假设地址占4个字节,根据你自己的机器作相应的调整
所以现在你可以像这样设置条件断点:
$gdb break write if *(int *)($esp + 4) == 1
再一次声明,假设地址占4个字节
寄存器,它将所有的数据都看成是
。因为GDB不允许直接将
型(这么做是对的),所以你需要先将
($esp + 4)
,然后再对其指针取值以获得文件描述符参数的值。
限定到特定字符串
接下来更加复杂一点,它是上一步的扩展,而且,它并不适用于所有的情况。传给
的字符串并不一定会完整的传给
,它可能会被分成更小的块然后一次性的写到文件中,调试stdout时请记住这一点,当然如果用短字符串的话应该没问题。(feihu注:调用
时并不会每次都调用
,而是会先把数据放到缓冲区,等缓冲区积累到一定量时才会一次性的写到文件中。如果想到立即写到文件中的话,需要调用
现在你必须再将这个断点加上一定的限制,当且仅当一个特定的字符串传给
时才中断程序。为了做到这一点,你可以对
的第二个参数
。从前面的表中可知,
指向的就是
,所以再给断点增加一个条件就变得很简单了:
$gdb break write if *(int *)($esp + 4) == 1 && strcmp("Hello World!\n", *(char **)($esp + 8)) == 0
$esp + n * sizeof(void *)
就代表了函数第n个参数的指针,这表明
指向的是一个指向字符串的指针,为了让它能够正确的运行,你需要做一些转换和取值操作。
64位系统的解决方案
64位系统需要采用
寄存器。(feihu注:对于32位系统,所有的函数参数是写在栈里面的,所以可以用前面介绍的办法。但是64位系统中函数的参数并未存放在栈中,它提供了更多的寄存器用于存放参数,请戳
$gdb break write if 1 == $rdi && strcmp((char *)($rsi), "Hello World!\n") == 0
注意这里没有了指针的转换操作,因为寄存器里面存的不是指向栈中元素的指针,它们存的是值本身。
经过上面的一系列步骤之后,你可以得到一个移植性不好的解决方案,在一些特定的平台和架构下,可以使用GDB在一个特定的字符串写到stdout时中断程序。
如果你有一个更好的解决方案,或者仅仅是另外一个替代方案,请在下面留言,并且/或者直接在Stack Overflow上
这个问题。还有,如果你有一种方案可以工作在其它平台或者架构下,请一定也给我留言。
原文的翻译就到上面,但是这里还可以再做一些改进。比如上面的
函数可以用下面的函数来代替:
对于你只想匹配前
个字符的情况非常有用
可以用来查找子字符串,这个非常有用,因为你不能确定你要查找的字符串到底是完整的一次由
输出的,还是经过几次
在缓存区合并之后才写到控制台的,因此我更加倾向这个方法
Windows上的解决方案
随后我想,能不能在Windows平台上也使用类似的方法,最终也成功了(x86-64位操作系统下的Win32和64位程序)。
对于所有的写文件操作来说,Linux最终都会调用到它的POSIX API
函数,Windows和Linux不一样,它提供的API是
,最终Windows上的调用都会用到它。但是,不像开源的Linux可以调试write,Windows无法调试WriteFile函数,所以也无法在WriteFile处设置断点。
但微软公开了部分VC的源码,所以我们可以在给出的源代码部分找到最终调用WriteFile的地方,在那一层设置断点即可。经过调试,我发现最后是
_write_nolock
调用了WriteFile,这个函数位于
your\VS\Folder\VC\crt\src\write.c
,函数原型如下:
/* now define version that doesn't lock/unlock, validate fh */
int __cdecl _write_nolock (
const void *buf,
unsigned cnt
对比Linux的write系统调用:
#include &unistd.h&
ssize_t write(int fd, const void *buf, size_t count);
每个参数都可以对应的起来,所以完全可以参照上面的方法来处理,在
_write_nolock
中设置一个条件断点即可,只有一些细节不一样。
可移植方案
很神奇的是Windows下面,在设置条件断点时可以直接使用变量名,而且在Win32和x64下面都可以。这样的话调试就变得简单了很多:
_write_nolock
处增加一个断点
:Win32和x64在这里有些许不同,Win32可以直接将函数名作为断点的位置,而x64如果直接设置在函数名处是无法中断的,我调试了一下发现原因在于x64的函数入口处会给这些参数赋值,所以在赋完值之前这些参数名还是无法使用的。我们这里可以有一个work around:不在函数的入口处设置断点,设置在函数的第一行,此时参数已经初始化,所以可以正常使用了。(即不用函数名作为断点的位置,而是用文件名+行号;或者直接打开这个文件,在相应的位置设置断点即可。)
设置条件:
fh == 1 && strstr((char *)buf, "Hello World") != 0
:但是这里有一个问题,我测试了
,对于前者,所有的字符串一次都写到了
_write_nolock
是一次传一个字符,这样也就无法使用后面比较字符串这个条件了。
只适用Win32的方案
当然,这里我们也可以采用前面介绍的方法,通过寄存器来设置断点的条件。同样由于平台的差异,这里分Win32和x64来讨论。
对于Win32程序,和前面介绍的Linux下使用GDB的方法基本一致。注意到函数前面的
,这种调用约定表明:
参数由右至左传递
调用方负责清理栈
非特殊情况下,会在函数名前加下划线来修饰
不执行任何大小写转换
。微软的网站上还有一个
来展示函数调用时参数在栈中的情况,结果请看
,它给出的每一种调用约定下寄存器和栈的使用情况。
知道这些之后,设置一个条件断点就变得非常容易了:
_write_nolock
处设置一个断点
增加条件:
*(int *)($esp + 4) == 1 && strstr(*(char **)($esp + 8), "Hello") != 0
同前面介绍的Linux下的方法一样,条件的第一部分是对
,只有当向
写数据时才中断。第二部分是针对
,当其中含有特定的字符串时满足中断条件。
只适用x64的方案
从x86到x64有两个重要的
,一是地址容量从32位变成了64位,二是增加了一些64位寄存器。因为这些寄存器的增加,x64就只使用
这种方式作为调用约定,这种方式会将前四个参数放到寄存器中,如果有更多参数的话,会存到栈中。
关于参数传递可以参考
,函数调用时前四个参数会依次放到:
当中,因此增加条件断点也变得很容易:
_write_nolock
处设置一个断点:
:这里直接在入口设置即可,不需要像前面可移植方案中介绍的那样设置到函数的第一行,因为寄存器在入口处已经有了正确的值。
设置条件:
$rcx == 1 && strstr((char *)$rdx, "Hello") != 0
是将所有的数据都看成是
,所以需要做一定的转换才可以使用。而这里的寄存器存的是参数的值,所以不需要这个转换。所以
中存的是一个指针,将它转成
之后即可表示字符串。
同样,这个方法也有一定的局限性,比如对于
,我还没有找到好的解决办法。
我也将这后面Windows上的方法发到
的评论中,算是给这个问题的一个扩展吧。如果你有更好的解决方案,请给我们留言或者直接在
于 Shenzhen
原文地址:, 感谢原作者分享。
您可能感兴趣的代码查看: 3066|回复: 9
注册时间最后登录在线时间34 小时积分204精华0帖子主题UID342185
初级工程师, 积分 204, 距离下一级还需 296 积分
注册时间积分204主题帖子UID342185
OKI5530sc针式打印机打的字有深有浅,一个字都有深有浅,换了打印头也不行,求大神支招
帖子永久地址:&<button type="submit" class="pn" onclick="setCopy('OKI5530sc针式打印机打的字有深有浅,一个字都有深有浅,换了打印头也不行,求大神...\nhttp://www.oachn.net/thread--1.html', '帖子地址已经复制到剪贴板您可以用快捷键 Ctrl + V 粘贴到 QQ、MSN 里。')">推荐给好友导航<font color="#、大家在,时遇到技术问题,请到技术讨论区发帖,上传资料请到上传区,下载不要使用迅雷等工具。
2、下载:、、、、、。
3、论坛导航:、、、、、。
3、网导航:、、、、、。
这是论坛默认签名,
注册时间最后登录在线时间3 小时积分12精华0帖子主题UID345203
技术员, 积分 12, 距离下一级还需 88 积分
注册时间积分12主题帖子UID345203
这是论坛默认签名,
注册时间最后登录在线时间34 小时积分204精华0帖子主题UID342185
初级工程师, 积分 204, 距离下一级还需 296 积分
注册时间积分204主题帖子UID342185
谢谢,色带架也换了还是一样的,不知道是哪里的事了&&
这是论坛默认签名,
注册时间最后登录在线时间276 小时积分176精华0帖子主题UID255950
初级工程师, 积分 176, 距离下一级还需 324 积分
注册时间积分176主题帖子UID255950
这是论坛默认签名,
注册时间最后登录在线时间796 小时积分12102精华0帖子主题UID315070
高级工程师, 积分 12102, 距离下一级还需 7898 积分
注册时间积分12102主题帖子UID315070
真没遇过这情况
这是论坛默认签名,
注册时间最后登录在线时间34 小时积分204精华0帖子主题UID342185
初级工程师, 积分 204, 距离下一级还需 296 积分
注册时间积分204主题帖子UID342185
就是这个样子的怎么调好了呢&&求大神
(55.12 KB, 下载次数: 18)
15:29 上传
点击文件名下载附件
这是论坛默认签名,
注册时间最后登录在线时间74 小时积分543精华0帖子主题UID333339
中级工程师, 积分 543, 距离下一级还需 457 积分
注册时间积分543主题帖子UID333339
换头问题依旧那就是主板问题。。
这是论坛默认签名,
注册时间最后登录在线时间183 小时积分129精华0帖子主题UID236297
初级工程师, 积分 129, 距离下一级还需 371 积分
注册时间积分129主题帖子UID236297
遇到同样情况&&5100的&&同求&&据说又可能是线缆的问题&&不知道是不是
这是论坛默认签名,
注册时间最后登录在线时间11 小时积分0精华0帖子主题UID344232
技术员, 积分 0, 距离下一级还需 100 积分
注册时间积分0主题帖子UID344232
感觉不怎么会修针式打印机
这是论坛默认签名,
注册时间最后登录在线时间109 小时积分11精华1帖子主题UID259025
技术员, 积分 11, 距离下一级还需 89 积分
注册时间积分11主题帖子UID259025
这是论坛默认签名,
优秀会员GG勋章
授予优秀会员(GG专用)。
连续三月优秀会员
授予连续三月优秀会员。
热心会员以上级别可佩带。
优秀会员以上可佩带。
热心会员勋章
在讨论区积极帮助会员、及时、正确的回答会员提出的问题。
积极发表原创文章,能够带动人气、并且经常发一些具有讨论意义的帖子。
热心宣传勋章
授予宣传推广论坛的会员。
资源贡献勋章
积极上传维修手册及技术资料。
Powered by

我要回帖

更多关于 mysql更改表的字符集 的文章

 

随机推荐