所谓调试(Dubug),就是跟踪程序的运行过程,从而发现程序的逻辑错误(思路错误),或者隐藏的缺陷(Bug)。 在调试的过程中,我们可以监控程序的每一个细节,包括变量的值、函数的调用过程、内存中数据、线程的调度等,从而发现隐藏的错误或者低效的代码。 我敢保证,每个人都会遇到逻辑错误,而且会经常遇到,初学者更是错的离谱,所以,必须掌握调试技能,没有选择的余地,没有学会调试就是没有学会编程!
调试器(Debugger)
调试需要借助专业的辅助软件------调试器(Debugger)。现在主流 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 的移植版,如果你不使用 VC/VS,GDB 将是一个不错的选择。
默认情况下,程序不会进入调试模式,代码会瞬间从开头执行到末尾。要想观察程序的内部细节,就得让程序在某个地方停下来,我们可以在这个地方设置断点。
所谓断点(BreakPoint),可以理解为障碍物,人遇到障碍物不能行走,程序遇到断点就暂停执行。
上图中,我们希望让程序在第 4 行代码处暂停执行,那么在第 4 行代码左侧的灰色部分单击鼠标即可插入断点。你也可以将光标定位到要暂停的代码行,然后按 F9 键插入断点。也可以在要暂停的位置单击鼠标右键,在弹出菜单中插入断点,如下图所示:
插入断点后,点击上方的"运行"按钮,或者按 F5 键,即可进入调试模式,如下图所示:
可以看到,程序虽然运行了,但并未输出任何数据,这是因为在输出数据之前就暂停了。同时,在 IDE 的上方出现了与调试相关的工具条,下方也多出了几个与调试相关的窗口:
调用堆栈可以看到当前函数的调用关系。
断点窗口可以看到当前设置的所有断点。
即时窗口可以让我们临时运行一段代码,后续我们会重点讲解。
输出窗口和我们之前看到的没有,用来显示程序的运行过程,给出错误信息和警告信息。
自动窗口会显示当前代码行和上一代码行中所使用到的变量。
局部变量窗口会显示当前函数中的所有局部变量。
线程和模块窗口暂时无需理会。
如果你的 VS 缺少某个窗口,可以通过 VS 上方的"调试"菜单调出,如下图所示:
注意:必须在调试状态下才能看到图中的菜单。
如果你希望关闭某个窗口,可以在窗口标题处单击鼠标右键,在弹出菜单中隐藏,如下图所示:
断点的真正含义
严格来说,调试器遇到断点时会把程序暂时挂起,让程序进入一种特殊的状态------中断状态,这种状态下操作系统不会终止程序的执行,也不会清除与程序相关的元素,比如变量、函数等,它们在内存中的位置不会发生变化。
关键是,处于中断状态下的程序允许用户查看和修改它的运行状态,比如查看和修改变量的值、查看和修改内存中的数据、查看函数调用关系等,这就是调试的奥秘。
继续执行程序
点击"运行"按钮或者按 F5 键即可跳过断点,让程序恢复正常状态,继续执行后面的代码,直到程序结束或者遇到下一个断点。
在调试过程中,按照上面的方法可以设置多个断点,程序在执行过程中每次遇到断点都会暂停,如下图所示:
删除断点
如果不希望程序暂停,可以删除断点。删除断点也很简单,在原有断点处再次单击鼠标即可,也可以将光标定位到要删除断点的代码行,再次按 F9 键,或者在右键菜单中删除,如下图所示
代替暂停语句
在 VS 下,程序运行结束后不会自动暂停(一闪而退),要手动添加暂停语句 system("pause");,如果大家觉得麻烦,也可以在代码最后插入断点,强制程序暂停。
设置了断点,就可以观察程序的运行情况了,其中很重要的一点就是查看相关变量的值,这足以发现大部分逻辑错误。
将下面的代码复制到源文件中:
1. #include <stdio.h>
2. int main(){
3. int value_int, array_int[3];
4. float value_float;
5. char* value_char_pointer;
6. //在这里插入断点
7. value_int = 1048576;
8. value_float = 2.0;
9. value_char_pointer = "Hello World";
10. array_int[0] = 379; array_int[1] = 94;
11. //在这里插入断点
12. return 0;
13. }
在第 7 行和第 12 行插入断点。运行到第一个断点时,在局部变量窗口可以看到各个变量的值:
可以看到,未经初始化的局部变量和数组的值都是垃圾值,是随机的,没有意义。双击变量的值,可以进行修改。
点击"运行"按钮或按 F5 键,程序会运行到下一个断点位置,在局部变量窗口可以看到各个值的变化:
更加快捷的方式
除了在窗口中查看变量,还有一种更加便捷的方法:在调试模式下,把鼠标移动到要查看的变量的上方,即可看他它的值。如下图所示:
如果是数组、指针、结构体等还可以展开,如下图所示:
这种查看变量的方式在实际开发中使用很多。
添加监视
如果你希望长时间观测某个变量,还可以将该变量添加到监视窗口。在要监视的变量处单击鼠标右键,弹出如下菜单:
选择"添加监视",在 VS 下方的监视窗口就可以看到当前变量:
这样,每次变量的值被改变都会反映到该窗口中,无需再将鼠标移动到变量上方查看其值。尤其是当程序稍大时,往往需要同时观测多个变量的值,添加监视的方式就会显得非常方便。