上节我们了解了使用打印函数输出调试信息的方法,正如文章中所提到的,一旦程序变得庞大了,我们可能要编写大量的调试输出语句,这无疑给我们加重了程序开发的负担。不过幸运的是,很多编写编译器的厂商或组织都编写了一种特殊的调试辅助软件——调试器,这种软件可以很大程度的方便我们的调试操作,它可以进行变量监视,变量查看/修改,修改程序运行位置等操作,调试器有着相当强大的功能,这套教程后面也主要是介绍调试工具的使用。
现在主流C/C++调试器有下面几种:
这里指的是 Visual Studio 自带的调试器,作为最先进的开发工具,Visual Studio 的 Remote Debugger 也是相当强大,用起来也比较方便,新手入门建议使用此调试器。
大名鼎鼎的 Windows 下的调试器,它的调试功能甚至超越了 Visual Studio 的 Remote Debugger,它还有一个命令行版本 (cdb.exe),但是这个命令行版本的调试器指令相对复杂,不推荐新手使用此调试器。
XCode 自带的调试器,Mac OS X 下开发必备调试器。
GNU 的一款相当强大的调试器,在 Linux 十分盛行,Windows 版本也有不少用户,使用起来比 cdb 简单一些。如果您不使用 Visual Studio ,这将是一个不错的选择。
调试器有命令行调试器(如 GNU 的 gdb 等),也有带 GUI 的调试器(如微软的 WinDbg),也有直接嵌入 IDE 的调试器(比如嵌入 Visual Studio 的 Remote Debugger),对于新手来说,Visual Studio 自带的调试器是用起来最方便的,后面我们也将以 Visual Studio 作为教学用 IDE。调试器的使用都是相似的,学会了 Visual Studio 的调试之后,您也能够很快的学会其他调试器的使用,笔者就是如此。
现在让我们来认识一下 Visual Studio 2013 的调试界面。
首先创建一个工程,编写完代码之后,注意编辑器上方的工具条:
在右边选择了 Debug 之后点击左边的 “本地 Windows 调试器” 即可开始调试。
常见疑问:为什么要选择这个“Debug”?
选择了 Debug 之后,程序编译的时候会加入调试信息以供调试器使用,这些信息包含了源文件路径、运行环境等,调试器对没有这些调试信息程序是无效的。注意,在发布程序时,请选择 Release,使用此模式构建程序不会包含调试信息,并且编译器会对代码进行优化。以适应实际使用环境。
接下来我们点击按钮(或者按F5)开始调试:
这就是 Visual Studio 的调试模式的窗口了(因个人设置可能有所不同),接下来我们介绍一下下方的几个调试相关窗口:
这个窗口显示的变量是由 Visual Studio 调试器在运行的时候自动检测的,程序调试过程中,Visual Studio 会检测与正在执行的语句相关的对象或变量,然后据此列出自动窗口的变量。在这个窗口中您可以查看或修改变量或对象的信息。
Visual Studio 调试器在运行过程中,会检测出当前运行的函数(方法)中的所有的所有局部变量。在这个窗口中您可以查看或修改这些局部变量或局部对象的信息。
这个窗口用于实时显示您在调试过程中添加监视的变量或对象的状态,在后面的教程中我们会讲解添加变量监视的方法。
这个窗口会显示当前函数的调用堆栈情况,默认情况下,它会显示类似下面的数据,这里面包含了函数的调用关系。在调试过程,这个窗口里的信息也是很有用的,通过它你可以知道程序运行到了哪里以及当前函数的相关信息。
在这个窗口中您可以十分方便的查看、管理整个工程的断点设置,后续教程我们也会教大家断点的设置及其作用。
通过这个窗口可以使用调试器的命令行模式,具体的使用方式可以到微软 MSDN Library 上搜索,本教程不再赘述。
这个窗口用于显示调试器的输出,包括触发了断点或跟踪点以及 OutputDebugString 函数输出的调试信息等。
对于 Visual Studio 调试器的介绍就到这里,接下来我们点击 “本地 Windows 调试器”开始调试。程序运行中 ...
待调试程序运行完成之后,您将会神奇的发现:什么都没发生,上文介绍的自动窗口也没有任何动静,这是为什么呢?原因很简单:我们还没有设置程序运行断点。在下一节,我们将重点介绍断点以及断点的设置。
接下来布置本节的一个小任务:
创建一个工程,插入如下代码,使用 Visual Studio 编译生成此工程,然后进行调试,注意,这里我们的目的不是调试,程序运行时我们把鼠标悬浮到调试窗口的各个按钮上,根据边上显示的气泡提示,我们可以对这个按钮的功能有大致的了解。
代码如下:
#include <stdio.h>
int main(){
printf("不要在本窗口按任意键!\n");
printf("把鼠标悬停到调试窗口的各个按钮上。\n");
printf("根据边上的气泡提示了解该按钮的用途!\n");
getchar();
return 0;
}
效果图如下: