GDB调试
程序中的语法错误通常可以在翻译阶段就能被诊断出来,但逻辑错误却很难被发现和纠正,比如在解决问题时使用了错误或者不完备的思路。在这种情况下,调试可能是唯一的救命稻草。通过设置适当的断点,你可以观察结果并和预期的结果进行比较以缩小问题代码的范围,并最终发现问题所在。
所谓调试(Debug),就是让代码一步一步慢慢执行,跟踪程序的运行过程。比如,可以让程序停在某个地方,查看当前所有变量的值,或者内存中的数据;也可以让程序一次只执行一条或者几条语句,看看程序到底执行了哪些代码。
在调试的过程中,我们可以监控程序的每一个细节,包括变量的值、函数的调用过程、内存中数据、线程的调度等,从而发现隐藏的错误或者低效的代码。
编译器可以发现程序的语法错误,调试可以发现程序的逻辑错误。所谓逻辑错误,是指代码思路或者设计上的缺陷。
现在主流C/C++调试器有下面几种:
(1)Remote Debugger:Remote Debugger 是 VC/VS 自带的调试器,与整个IDE无缝衔接,使用非常方便,初学者建议使用该调试器,本教程也以 VS2010 为例讲解调试技巧。
(2)WinDbg:大名鼎鼎的 Windows 下的调试器,它的功能甚至超越了 Remote Debugger,它还有一个命令行版本(cdb.exe),但是这个命令行版本的调试器指令比较复杂,不建议初学者使用。
(3)LLDB:XCode 自带的调试器,Mac OS X 下开发必备调试器。
(4)GDB:Linux 下使用最多的一款调试器,也有 Windows 的移植版。
GDB 是 Linux 下的 C/C++ 程序调试工具,它开源免费,功能强大,但是命令众多。虽然 Linux 系统下读者编写 C/C++ 代码的 IDE 可以自由选择,但是调试生成的 C/C++ 程序一定是直接或者间接使用 GDB。
GDB调试流程:
1、编译文件
使用 GCC 编译源文件:$ gcc main.c -o main.out -g
首先使用 GCC 来编译 main.c,编译的时候使用-g选项,它的目的是向可执行程序中加入调试信息,包括源代码、符号表等,GDB 需要这些额外的信息来完成调试工作。
此外还建议关闭编译器的程序优化选项。编译器的程序优化选项一般有五个级别,从 O0 ~ O4, O0 表示不优化,从 O1 ~ O4 优化级别越来越高,O4 最高。这样做的目的是为了调试的时候,符号文件显示的调试变量等能与源代码完全对应起来。
2、 启动 GDB 调试器
接下来启动 GDB 并调试 main.out:$ gdb main.out

$ gdb main.out -silent

选项-silent用于屏蔽 GDB 的前导信息,否则它会在屏幕上打印一堆免责条款。
启动 GDB 后,它输出的信息表明已经读入了 mian.out 的符号表。接下来,GDB 会显示自己的提示符(gbd),提示并等待你输入调试命令。
3、输入调试命令开始调试
(1)l 或者list:显示源文件内容
l 命令默认每次显示 10 行源代码,但我们关心的那一行显然还没有出来。为此,可继续使用 l 命令来显示后面的行。
(2)b 或者break:设置断点
调试一个程序的时候,应该在我们关注的地方,或者在故障点的前边设置一个断点(Breakpoint),让程序执行到这里停下来,这样我们就可以慢慢地用别的调试命令进行观察。
在 GDB 中,设置断点的方法很多,包括在指定的内存地址处设置断点、在源代码的某一行设置断点,或者在某个函数的入口处设置断点,等等。
b+函数名 设置对应函数为断点 b+行号 设置对应行号为断点 b+文件名:函数名 设置某个文件中的某个函数为断点 b+文件名:行号 设置某个文件中的第几行为断点 tbreak+行号或函数名 设置临时断点,达到后自动删除 b+行号+if+条件 用于设置条件断点,在循环中使用非常方便 b+偏移量 在当前位置的后 b-偏移量 b+0x.. 以内存地址作为断点 info b 查看断点处的情况
(3)删除断点
delete 删除所有断点 delete+断点编号 删除对应编号的断点 clear+行号 删除对应行号断点 delete+(编号起点-编号终点) 删除起点和终点的所有断点(包括起点和终点) disable+断点编号 可以禁用断点 clear clear 函数名 clear 行号 clear 文件名:行号 clear 文件名:函数名
(4)r或者run:执行程序
一旦设置了断点,下一步就是用r或者run命令执行被调试的程序,执行后会自动在第一个断点处停下来.
(5)p 或者print:打印变量的值
GDB 的 p 命令用于打印一个表达式的值,GDB 先计算表达式的值,并把它保存在一个存储区中,存储区的名字用$外加数字来表示,并且这个数字会随着调试过程的进行而不断递增(这意味着存储区也是不断开辟的)。
注意,在你的计算机上,变量 n 和 sum 的当前值可能和这里显示的不同。这很好理解,内存是反复使用的,当一个程序终止后,它占用的内存会分配给其他程序使用;当一个变量不再使用后,它占用的内存也会重新分配,并成为另一个变量。因为变量 n 和 sum 刚刚分配,还没有往里面保存任何数值,故它们的内容是随机的,是其他程序或者变量用过的垃圾值。
(6)watch:观察变量的值
在某一循环处,如果想观察一个变量的变化情况,就可以使用watch来观察变量的变化情况。例如:watch i 观察变量i的值 。
awatch+变量 设置一个观察点,当变量被读出或写入时程序被暂停 rwatch+变量 设置一个观察点,当变量被程序读时,程序被暂停 watch+变量 同awtch
(7) n或者next:单步调试
调试命令n或者next用于继续执行源文件中的下一行。
(8)c或者continue:继续执行程序
用命令c或者continue可以持续执行程序,直至遇到断点或者程序结束。
(9)q或者quit:退出调试
用q或者quit可以结束本次调试工作,这将使得调试器 GDB 结束运行并返回到操作系统。

浙公网安备 33010602011771号