调试技巧之调用堆栈 (一)

2014-11-24 12:03:58 · 作者: · 浏览: 4

在计算机科学中,Callstack 是指存放某个程序的正在运行的函数的信息的栈。Call stack 由stack frames 组成,每个stack frame 对应于一个未完成运行的函数。

在当今流行的计算机体系架构中,大部分计算机的参数传递,局部变量的分配和释放都是通过操纵程序栈来实现的。栈用来传递函数参数,存储返回值信息,保存寄存器以供恢复调用前处理机状态。每次调用一个函数,都要为该次调用的函数实例分配栈空间。为单个函数分配的那部分栈空间就叫做 stack frame,也就是说,stack frame 这个说法主要是为了描述函数调用关系的。

Stackframe 组织方式的重要性和作用体现在两个方面:第一,它使调用者和被调用者达成某种约定。这个约定定义了函数调用时函数参数的传递方式,函数返回值的返回方式,寄存器如何在调用者和被调用者之间进行共享;第二,它定义了被调用者如何使用它自己的 stack frame 来完成局部变量的存储和使用。

简单介绍

调试是程序开发者必备技巧。如果不会调试,自己写的程序一旦出问题,往往无从下手。本人总结10年使用VC经验,对调试技巧做一个粗浅的介绍。希望对大家有所帮助。

今天简单的介绍介绍调用堆栈。调用堆栈在我的专栏的文章VC调试入门提了一下,但是没有详细介绍。

首先介绍一下什么叫调用堆栈:假设我们有几个函数,分别是function1,function2,function3,funtion4,且function1调用function2,function2调用function3,function3调用function4。在function4运行过程中,我们可以从线程当前堆栈中了解到调用他的那几个函数分别是谁。把函数的顺序关系看,function4、function3、function2、function1呈现出一种“堆栈”的特征,最后被调用的函数出现在最上方。因此称呼这种关系为调用堆栈(callstack)。

当故障发生时,如果程序被中断,我们基本上只可以看到最后出错的函数。利用call stack,我们可以知道当出错函数被谁调用的时候出错。这样一层层的看上去,有时可以猜测出错误的原因。常见的这种中断时ASSERT宏导致的中断。

在程序被中断时,debug工具条的右侧倒数第二个按钮一般是callstack按钮,这个按钮被按下后,你就可以看到当前的调用堆栈。

实例一:介绍

我们首先演示一下调用堆栈。首先我们创建一个名为Debug的对话框工程。工程创建好以后,双击OK按钮创建消息映射函数,并添加如下代码:

void CDebugDlg::OnOK()

{

// TODO: Add extravalidation here

ASSERT(FALSE);

}

我们按F5开始调试程序。程序运行后,点击OK按钮,程序就会被中断。这时查看call stack窗口,就会发现内容如下:

CDebugDlg::OnOK() line176 + 34 bytes

_AfxDispatchCmdMsg(CCmdTarget* 0x0012fe74 {CDebugDlg}, unsigned int 1, int 0, void (void)* 0x5f402a00`vcall'(void), void * 0x00000000, unsigned int 12, AFX_CMDHANDLERINFO *0x00000000) line 88

CCmdTarget::OnCmdMsg(unsigned int 1, int 0,void * 0x00000000, AFX_CMDHANDLERINFO * 0x00000000) line 302 + 39 bytes

CDialog::OnCmdMsg(unsignedint 1, int 0, void * 0x00000000, AFX_CMDHANDLERINFO * 0x00000000) line 97 + 24bytes

CWnd::OnCommand(unsignedint 1, long 656988) line 2088

CWnd::OnWndMsg(unsignedint 273, unsigned int 1, long 656988, long * 0x0012f83c) line 1597 + 28 bytes

CWnd::WindowProc(unsignedint 273, unsigned int 1, long 656988) line 1585 + 30 bytes

AfxCallWndProc(CWnd *0x0012fe74 {CDebugDlg hWnd= }, HWND__ * 0x001204b0, unsigned int 273,unsigned int 1, long 656988) line 215 + 26 bytes

AfxWndProc(HWND__ *0x001204b0, unsigned int 273, unsigned int 1, long 656988) line 368

AfxWndProcBase(HWND__* 0x001204b0, unsigned int 273, unsigned int 1, long 656988) line 220 + 21bytes

USER32! 77d48709()

USER32! 77d487eb()

USER32! 77d4b368()

USER32! 77d4b3b4()

NTDLL! 7c90eae3()

USER32! 77d4b7ab()

USER32! 77d7fc9d()

USER32! 77d76530()

USER32! 77d58386()

USER32! 77d5887a()

USER32! 77d48709()

USER32! 77d487eb()

USER32! 77d489a5()

USER32! 77d489e8()

USER32! 77d6e819()

USER32! 77d65ce2()

CWnd::IsDialogMessageA(tagMSG* 0x004167d8 {msg=0x00000202 wp=0x00000000 lp=0x000f001c}) line 182

CWnd::PreTranslateInput(tagMSG* 0x004167d8 {msg=0x00000202 wp=0x00000000 lp=0x000f001c}) line 3424

CDialog::PreTranslateMessage(tagMSG* 0x004167d8 {msg=0x00000202 wp=0x00000000 lp=0x000f001c}) line 92

CWnd::WalkPreTranslateTree(HWND__* 0x001204b0, tagMSG * 0x004167d8 {msg=0x00000202 wp=0x00000000 lp=0x000f001c})line 2667 + 18 bytes

CWinThread::PreTranslateMessage(tagMS