在之前的课程1.11中,我们学习了怎么使用debugger工具来定位出现问题的地方。然而通过步进调试只能debugger用途的一半.debugger也可以用来跟踪你的变量的值。
我们下面的例子使用的是Visual Studio的debugger工具,如果你使用的是其他的IDE那么调试工具的使用可能不太一样,但是基本大同小异,你只需要找到相应的位置即可。
调试之前,确保你的程序处于调试模式。
看变量的值:
看变量的值就是当程序处于debug状态的时候,可以检查变量的值的变化。大多数debugger都提供了这种方式,让我们看一个简单的例子:
#include "stdafx.h"
#include <iostream>
int main()
{
int x =1;
std::cout << x << " ";
x = x + 1;
std::cout << x << " ";
x = x + 2;
std::cout << x << " ";
x = x + 4;
std::cout << x << " ";
return 0;
}
这个程序非常简单就是输出:1 2 4 8
首先让我们使用调试到光标处的命令,debug第一个std::cout。
这个时候x被赋值为1了,所以当我们检查的时候,我们就会发现1.最简单的调试方法就是将鼠标放到x的地方,这个时候就会显示1了。
请注意你可以将变量放到任何x的地方,而不只是第一行运行到的地方。
如果你使用的是visual stadio你还可以使用快速查看项,选择变量x,然后右键选择快速监视即可。
这将会打开一个子窗口如下:
继续关闭快速查看窗口。
现在让我们看一下该变量的变化,当我们单步执行调试命令的时候。选择step over两次,这样就会跑到下一次输出的地方。再次看x的值,此时都是2了。
观察窗口:
如果你想在某个特定的点观察某一个值的变化规程,那么使用鼠标或者右键watch就足够了。但是对于当你重新运行代码的时候,来观察变量的值来说这不是一个有效的办法。因为当你运行的时候,往往比较难选中变量的值。
为了解决这个问题,所有的IDE都提供了另一个特性,叫做watch窗口。watch窗口是一个添加了你自己选择变量的窗口,这个变量将会实时随着程序而变化。一般情况下watch window已经在你的IDE中显示了,如果没有显示的话,你可以通过调整你的IDE显示来显示出来。visual stadio中是调试->window->debug window->监视。
现在上面是空白的,因为你还没有添加任何的变量进去。有两种不同的方法来设置变量。
1.直接点击name栏,添加
2.选择你程序中的变量,右键点击添加。
添加x进去之后,你会看到:
现在逐步调试来看变量的变化情况。
请注意超出范围的变量,变量定义了但是没有使用。如果变量又在范围之后,我们会重新显示变量的值。
使用watch窗口是最好观察变量的值的方法。
调用栈窗口:
现代的调试器会包含一个非常有效的调试窗口对你调试程序来说非常有用,这个窗口叫做堆栈接口。
当你的程序调用一个函数的时候,你已经知道他会储存现在的地址,让函数去调用并返回。但是函数怎么知道返回给谁呢?答案是他会记录跟踪堆栈信息。
调用堆栈是所有被调用到当前执行点的函数的列表,调用堆栈包含一个所有调用函数的入口,包括那些行正在执行。当一个新的函数要执行的时候,函数被添加到调用栈的最上面。当函数返回值以后,就从栈的最上面删除。空hi全回到调用的函数。
如果你没有发现调用栈的窗口,你可以debug->window->call stack
让我们看一个简单的例子:
#include "stdafx.h"
#include <iostream>
void CallC()
{
std::cout << "C called" << std::endl;
}
void CallB()
{
std::cout << "B called" << std::endl;
CallC();
}
void CallA()
{
CallB();
CallC();
}
int main()
{
CallA();
return 0;
}
在CallC函数的地方添加一个断点,进入调试模式。程序会执行到你添加断点的地方。
尽管你知道该程序正在执行CallC,实际上有两个函数会调用到CallC。一个在CallB里面,一个在CallA里面。现在到底哪一个函数调用到了CallC,堆栈就会告诉我们。
请注意你的行号可能不同,就像在main函数中调用的堆栈函数一样。
程序从main函数开始,然后调用CallA函数,然后调用CallB函数,然后调用CallC函数。你可以双击调用行,查看一些详细的信息。一些IDE会直接帮你跳到相应的函数中。
继续调试,堆栈会再次调用到CallC,这次是CallA调用的。你会看到下面的内容:
结论:
恭喜你,你已经了解了怎么去debugger你的程序。通过stepping,breakpoint,watches 和 call stack四种方法。,基本上可以定位所有的问题。想很多事情一样,使用调试器需要经验和错误的累计。然而你的程序越大,程序debugger的重要性也就越大,所以这个绝对值得你花时间去投资。