wenmo8 发布的文章

当处于调试模式中断下,我们可以通过Watch窗口快速查看我们想观察的变量、表达式的值。

打开

  • 通过菜单栏方式
  • 通过代码窗口右键
    选中表达式/变量
  • 快捷键
    先按Ctrl+Alt+W
    状态栏显示

    在按下数字键1,2,3,4
    显示对应的窗口

窗口使用

 

具体操作跟其他变量窗口操作一样。只是右键菜单多几个选项

 

  • Delete Watch
    删除选择的变量或表达式的观察
  • Clear All
    删除所有的变量和表达式

说明

Watch窗口可以在用户单步调试代码时监视变量的值。尽管一共有4个窗口,但大度数情况使用一个窗口就够了。4个独特的窗口意味着可以把不同类型的变量分别显示在不同窗口。如果开发人员处理的是涉及多个类的复杂问题,这种显示方法就会非常有用。

Watch窗口可以随时任意添加变量、表达式,也可以删除不观察的变量、表达式。

在编写代码或调试应用程序时,为了测试某个功能或者显示应用程序的工作状态,经常需要计算简单表达式的值。使用Immediate窗口可以很方便地实现这种操作。该窗口可以计算用户输入的表达式值。

打开

  • 菜单栏方式
  • 快捷键
    Ctrl+Alt+I

窗口的使用

输入命令

大于号 (>) 作为新行提示符出现在“命令”窗口的左边缘。使用向上键和向下键可滚动显示以前发出的命令。

 

在“监视”、“自动”和“局部变量”窗口中,可以使用格式说明符更改值显示的格式。还可以在即时窗口、命令窗口、跟踪点甚至源窗口中使用格式说明符。如果在这些窗口中暂停,表达式结果将显示在数据提示中。数据提示根据格式说明符显示。

设置格式说明符

我们将使用下面的示例代码:

intmain() {int my_var1 = 0x0065;int my_var2 = 0x0066;int my_var3 = 0x0067;
}

除了在调试会话中检测变量的内容外,还应仔细评估代码的逻辑,确保所有代码按期望的顺序执行。Vsual Studio提供一组窗口,他们显示了暂停程序执行时所加载和执行的代码。这样就可以更好的理解代码的运行时行为,快速找出逻辑错误。

这些窗口有Call Stack窗口、Threads窗口、Moduls窗口和进程窗口。今天介绍Call Stack窗口。

打开

  • 通过菜单栏打开
  • 通过快捷键
    Alt+7

窗口的使用

 

  •  Call Stack
    线程当前的调用栈帧序列。
  • Language
    当前栈帧的语言

在本窗口右键点击,弹出如下菜单

其他说明

随着应用程序变得越来越复杂,程序的执行路径也变得难以跟踪。深层继承树和接口的使用会掩盖执行路径。此时,Call Stack窗口的使用就变得非常必要。借助Call Stack窗口,很容易跟踪执行路径,并判断当前执行的方法是从哪里调用的。

高级断点语法 

高级断点语法由两部分组成:

  • 上下文部分.
    用函数,源文件和二进制模块来指定上下文,上下文的表示方法: {[函数],[源文件],[二进制模块]}。
  • 位置,表达式,变量或Windows消息条件.  

必须指定唯一的,足够的上下文信息才能获取断点位置.如:
在TEST.CPP的20行设一位置断点,语法为:{,TEST.CPP,}.20
如A.DLL或B.DLL都使用了该行,又只想在B.DLL的调用中触发,则必须使用:{,TEST.CPP,B.DLL}.20. 

VC调试器中可直接输入上下文语法:Breakpoints对话框的Location选项卡BreakAt编辑框中。更容易的方法是使用BreatAt框右的箭头打开菜单,选择Advanced项,然后在Context框中输入断点的相应信息.  如想在一个绝对地址上中断,直接在BreakAt框中输入地址就行。

任何函数上快速中断  

将函数名输入BreadAt框中.如果是C++代码,同时还需要类限定符.支持重载了的函数,调试器会列出所有满足条件的函数供选择,如输入时提供足够的信息,完全可略过选择过程.如输入:"CString::operator=(const  
char   *)"可唯一确定要中断的函数.  

在系统或DLL输出的函数中设置断点

在程序中从DLL输入的函数中设置一个断点可能是毫无作用的,调试器需要知道在何处可以找到该函数上下文信息,同时,函数名取决于是否加载了DLL的符号.只有在W2K以上版本中才能在系统DLL中设置断点--原因在于其它系统没有提供边写入边复制保护的功能,若一定要启用这种方法,必须要有COFF(Common  
Object   File   Format),并在调试器中输出启动的装载----在Options对话框的Debug页,将Load  
COFF   &   Exports选中。
VC调试器用分级的符号信息法,完整的符号的级别高于不太完整的。PDB(Program  

Database)文件具有所有可能的源码行,函数,变量和类型信息,优先级便高于COFF/DBG文件,后者只有公用函数符号,而COFF/DBG文件高于输出名称,输入的名称是一种伪符号。
调试时,如DEBUG窗口输出:装载DLL的符号,则说明符号已被装入;否则说明没有装载DLL的符号。
没有装入符号时,使用的位置字符串是DLL输出的名称,可能用DUMPBIN程序查看这个名称:DUMPBIN   /EXPORTS   DLLname.例:在LoadLibraryA中设置中断:"{,,Kernel32.dll}LoadLibraryA".  
如装入了符号,则要根据输出函数和调用协议来计算函数名.如上例,LoadLibraryA使用__stdcall调用协议,据该协议,函数名以下划线为前缀,所跟有进栈的字节数为后缀的@号.一般说来,参数个数*4,就是参数占用栈空间的总字节数,LoadLibary的名称便是:_LoadLibraryA@4,故最后的语法是:或"{,,Kernel32.dll}_LoadLibraryA@4"  。

位置断点修饰符

跳跃计数

功能是执行断点但不在断点处停止,直到执行完了一个特定的次数为止。使用中首先设置一个标准的位置断点,打开BreadPoint对话框,选中该断点,单击Condition,然后在弹出的对话框最下面的编辑控件中输入次数。 只有当程序全速运行时,未执行的循环次数才有用.单步执行跨过断点时不会更新跳跃计数。
例:已知循环可能崩溃,但不清楚在哪次循环时,输入远远大于总循环次数的跳跃计数修饰符,则在崩溃时可打开Breakpoint框,其中将列出还未执行的循环次数,与总次数相减就可得已执行的次数。

条件表达式

只有表达式为真时触发.Breakpoint框Condition按钮,选第一个编辑框,输入表达式即可.规则:  
.只可使用C类型比较运算符.  
.表达式中不能调用任何函数.  
.表达式中不能包含任何宏值.  
表达式为@TIB=Thread  
Infomation   Block   Linear  
Address,则程序只在该特定线程中才会中断.例:线程@TIB地址值为0E000,则输入"@TIB==0xE000",则在切换到该线程时中断.对W98,可用@FS=thread  
specific   value.  
如在某特定错误后中断,则可用@ERR,如"@ERR=2"表示在最后错误为ERROR_FILE_NOT_FOUND.除@CLK外,所有可在WATCH窗口中使用的伪寄存器均可用于条件表达式.  

条件表达式可与跳跃断点组合使用. 

变量更改

在变量更改时中断程序.只有当位置断点执行时才能检查变量.常用用调用栈高层的函数中发现出错,需要深入调用栈,压缩范围找出根源时.  添加时在Breakpoint框第一个编辑框中输入变量名(可以是指针指向听对象:*p),在第二个编辑框中输入要查看的项目数量. 

全局表达式和条件断点

调试器可监控某一地址和该地址上的1,2或4字节的内容.如可用硬件调试寄存器,则不影响速度;否则程序将单步执行ASM指令并在每一步中检查条件,这将严重影响程序运行速度.  
总共有4个调试寄存器.硬件调试寄存器不能处理超过1个双字长的引用.确保利用硬件调试寄存器的最好方法是使用表达式和数据更改位置的实际地址值.例如:g_szGlobal是全局数组指针,地址为0x5000,则在Breakpoint对话框中DATA选项卡中将表达式断点设为"*(char*))0x5000=='G'",但如果写为"WO(0x5000)=='G',则用不到硬件调试寄存器,会单步执行每条指令.  
与全局表达式断点类似,使用变量的16进制地址给定长指针计算地址,并将要查看的单元数设为1,则全局变量断点可发挥最付佳功效.如上例要在变量改动时中断,则输入:"*(long*)0x5000". 

WINDOWS消息断点

Breakpoint框的Message页.需要指定一个窗口过程,注意:MFC世界中AfxWndProc是多数窗口的一个窗口过程,所以总会在该断