程序调试技巧之调用堆栈
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
调试技巧之调用堆栈
在计算机科学中,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+34bytes
_AfxDispatchCmdMsg(CCmdTarget*0x0012fe74{CDebugDlg},unsigned int1,int0, void(void)*0x5f402a00`vcall'(void),void*0x00000000,unsigned int12, AFX_CMDHANDLERINFO*0x00000000)line88
CCmdTarget::OnCmdMsg(unsigned int1,int0,void*0x00000000, AFX_CMDHANDLERINFO*0x00000000)line302+39bytes
CDialog::OnCmdMsg(unsignedint1,int0,void*0x00000000,AFX_CMDHANDLERINFO *0x00000000)line97+24bytes
CWnd::OnCommand(unsignedint1,long656988)line2088
CWnd::OnWndMsg(unsignedint273,unsigned int1,long656988,long*0x0012f83c) line1597+28bytes
CWnd::WindowProc(unsignedint273,unsigned int1,long656988)line1585+30 bytes
AfxCallWndProc(CWnd*0x0012fe74{CDebugDlg hWnd=???},HWND__*0x001204b0, unsigned int273,unsigned int1,long656988)line215+26bytes AfxWndProc(HWND__*0x001204b0,unsigned int273,unsigned int1,long656988) line368
AfxWndProcBase(HWND__*0x001204b0,unsigned int273,unsigned int1,long
656988)line220+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=0x00000202wp=0x00000000 lp=0x000f001c})line182
CWnd::PreTranslateInput(tagMSG*0x004167d8{msg=0x00000202wp=0x00000000 lp=0x000f001c})line3424
CDialog::PreTranslateMessage(tagMSG*0x004167d8{msg=0x00000202 wp=0x00000000lp=0x000f001c})line92
CWnd::WalkPreTranslateTree(HWND__*0x001204b0,tagMSG*0x004167d8 {msg=0x00000202wp=0x00000000lp=0x000f001c})line2667+18bytes CWinThread::PreTranslateMessage(tagMSG*0x004167d8{msg=0x00000202 wp=0x00000000lp=0x000f001c})line665+18bytes