章节目录

调用堆栈

本节阅读量:

现代调试器还包含一个非常有用的调试信息窗口,即调用堆栈窗口。

当程序调用函数时,您已经知道它会记录当前的位置,然后跳转到被调用的函数中执行,执行完毕后再返回。那么程序是如何知道该返回到哪里的呢?答案是它通过调用堆栈来保持记录。

调用堆栈是为到达当前执行点而依次调用的所有函数的列表。调用堆栈包含每个被调用函数的信息,以及函数返回时将回到哪一行的标记。每当调用新函数时,该函数都会被添加到调用堆栈的顶部。当当前函数返回给调用者时,它会从调用堆栈的顶部移除,控制权将返回到它下面的函数。

调用堆栈窗口是显示当前调用堆栈的调试器窗口。如果看不到调用堆栈窗口,则需要在 IDE 中设置将其显示出来。

让我们使用示例程序来查看调用堆栈:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
#include <iostream>

void a()
{
	std::cout << "a() called\n";
}

void b()
{
	std::cout << "b() called\n";
	a();
}

int main()
{
	a();
	b();

	return 0;
}

在此程序的第5行和第10行上放置断点,然后启动调试模式。因为首先调用的是函数 a,所以程序将首先命中第5行上的断点。

此时,您应该看到这样的内容:

调用堆栈

您的IDE显示的内容可能会有一些差异:

  1. 函数名和行号的格式可能不同
  2. 您的行号可能略有不同(相差1)
  3. 您可能会看到许多其他名字奇怪的函数,而不是[外部代码]。

这些差异无关紧要。

这里相关的是前两行。从下往上,我们可以看到函数main首先被调用,然后函数a被调用。

函数 a 旁边的第5行显示了当前执行点的位置(与代码窗口中的执行标记一致)。第二行上的第17行表示当控制权返回到函数 main 时将继续执行的行。

现在,点击继续,推进到下一个断点,即第10行的断点。调用堆栈应该会更新以反映新的情况:

调用堆栈

您会注意到,函数 b 现在位于调用堆栈的顶部,表明函数 b 是当前正在执行的函数。请注意,函数 a 已经不在调用堆栈上了,这是因为函数 a 在返回时已从调用堆栈中移除。

现在,点击继续,我们将再次命中第5行上的断点(因为函数b调用函数a)。调用堆栈如下所示:

调用堆栈

现在调用堆栈上有三个函数:(从下到上)main 调用了函数 b,而 b 又调用了函数 a。

当断点被命中时,如果您想知道程序是通过哪些函数调用到达代码中该特定位置的,调用堆栈窗口与断点配合使用会非常有帮助。


结论

恭喜您,您现在已经了解了使用集成调试器的基础知识!借助单步执行、断点、监视和调用堆栈窗口,您已经具备了调试几乎任何问题的基础。和许多事情一样,要想熟练地使用调试器,需要一些练习和尝试。但是,我们再次强调,花在学习如何有效使用集成调试器上的时间,将会为您在调试程序时节省大量时间!


3.7 监视变量

上一节

3.9 在问题变成问题前进行避免

下一节


本节目录