监视变量(Watching Variables)

当程序停在一个断点处时,用户做些什么呢?通常用户在断点处停下来是要检查变量的值,某个变量的值是否与预料的取值相同?或者某个变量取什么值(事先并不知道这个变量的取值)。

Watch List窗口的作用是使用户能检查变量的值。编程人员常常忽视这个简单而又根本的特性,因为他们没有花时间来完整地学习调试器的使用。用户可添加任意多的变量到Watch List中。下图就是调试会话期间的Watch List窗口。

变量名和变量值都显示在Watch List中。

Tooltip表达式求值(Tooltip Expression Evaluation)

调试器和Code Editor有一个很好的特性,它使检查变量值的工作变得更容易。这个特性就是Tooltip表达式求值器(expression evaluator),其缺省状态是打开,因此用户不需要做任何事情就能使用它。如果需要,也可以通过Editor Properties对话框的Code Insight页面来关闭它,如下图:

那么,什么是Tooltip表达式求值呢?它是这样工作的:当程序停在一个断点处,用户把编辑光标移到一个变量上,就会弹出一个提示窗口,其中显示该变量的当前值。这样就使快速检查变量的工作变得更容易,只需将光标移到变量上并稍等片刻。

Tooltip evaluator求值器对于不同的变量类型由不同的显示。对于常规数据成员(Integer、Char、Byte、String等等),显示变量的实际值;对于动态创建的对象(例如一个类的实例),Tooltip evaluator显示记录的全部元素。如下图所示:

Note

有时候Tooltip evaluator好像工作不正常。例如,若将编辑光标移到一个作用域外的变量上时,就不会显示提示窗口,因为Tooltip evaluator 无任何信息可显示。被编辑器优化过的变量也可能不能显示正确值。

当光标位于with块中时,Tooltip evaluator也不工作。例如,看下面这段代码:

varpp: Point;
beginwith  pp dobeginx := 20;y := 40;end;Caption := IntToStr(pp.x);
end;

如果把光标放到变量x上,Tooltip evaluator不会显示x的值,因为x属于with语句(Point变量)。如果将光标移到变量Point上,调试器会显示Point的值(包括x字段)。如下图:

Tooltip 表达式求值器很有用的,别忘记使用它。

Watch List快捷菜单(The Watch List Context Menu)

正如前面讲到的每一个Delphi窗口一样,Watch List也有它自己的快捷菜单。如下描述:

Edit Watch——打开Watch Properties对话框修改监视项属性
Add Watch——打开Watch Properties对话框新监视项
Enable Watch——启用一个已经禁用的监视项
Disable Watch——禁用一个已启用的监视项
Delete Watch——删除一个监视项
Enable All Watches——启用所有已经禁用的监视项
Disable All Watches——禁用所有已经启用的监视项
Delete All Watches——删除所有监视项
Add Group——增加一个监视组
Delete Group——删除一个监视组
Move Watch to Group——移动监视项到组
Stay On Top——使Watch List窗口始终在最上层

Inspect——显示选中的监视项的有关信息
Break When Changed——当监视窗口中的变量改变时,调试器将终端。监视变量以红色显示,表示Break When Changed起作用。
Dockable——窗口是可泊位。

使用Watch Properties对话框(Using the Watch Properties Dialog Box)

当用户增加或编辑监视项时,要使用Watch Properties对话框。如上图显示的是正在编辑pp变量的Watch Properties对话框。

位于对话框顶部的【Expression字段】,是用户输入要编辑或增加到Watch List中的变量名的地方,这个字段是一个组合框,可以用来选取以前用过的监视项。

但用户要检查数组时,使用【Repeat count字段】,比如,有一个20个整数元素的数组,要检查数组的头10个整数,可在【Expression字段】中输入数组的第一个元素(例如Array[0]),再在【Repeat count字段】中输入10。数组的头10个元素就会显示在Watch List中。如下图pp为有20个元素的整型数组:

Note

如果将数组名增加到Watch List中,则数组的全部元素都会显示在Watch List中。当要查看数组的部分元素时,使用【Repeat count字段】。

仅当检查浮点数时,采使用【Digits字段】;在此输入显示浮点数时要显示的有效位数,有效位后面的余数作四舍五入处理。【Enabled字段】确定监视项是否当前启用。

Watch Properties对话框上的其余选项都是显示选项。每一种数据类型都有一种缺省显示类型,当用户选中【Default】时,就使用缺省显示类型,Default查看选项的默认状态时“选中”的。选择其他的查看选项,就以其他方式查看数据。如下图:

要修改一个监视项,可在Watch List中点击该项,然后在右键快捷菜单中选择【Edit Watch…】菜单项,也可双击该监视项,快速打开Watch Properties对话框。

启用和禁用监视项(Enabling and Disabling Watch Items)

就像使用断点时一样,Watch List中每项都可被启用或禁用。当一个监视项被禁用时,它会变灰,并且它的值显示为<disabled>。如下图:

要禁用一个监视项,可点击Watch List中该项的名字,并从Watch List快捷菜单中选择【Disabled Watch】菜单项;要启用该监视项,就从快捷菜单中选【Enabled Watch】菜单项。

Note

用户可能希望禁用当前不使用但以后要使用的监视项。在调试过程中,Watch List中的许多有效监视项会减慢程序执行速度,因为每当一个代码行执行时,所有Watch List变量都要更新。

向Watch List中添加变量(Adding Variables to the Watch List)

可用多种方法往Watch List中添加监视项。最快速的方法是点击Code Editor中的变量名,然后从Code Editor的快捷菜单中选择【Debug | Add Watch at Cursor】或按【Ctrl + F5】键,该监视项就会被立即增加到Watch List中。如果需要,用户可以编辑该监视项,修改其属性。

要增加一个变量到Watch List中而又不想在源文件中找出该变量时,可从主菜单选择【Run | Add Watch】菜单项;当Watch Properties对话框弹出后,输入要增加到Watch List中的变量名并点击OK。

Note

虽然可将类实例变量添加到Watch List中,但显示的值可能无用。如下图:

应该使用Debug Inspector查看类的所有数据成员。

使用Watch List(Using the Watch List)

当碰到断点时,Watch List显示其中所有变量的当前值,如果当前没有打开Watch List窗口,可从主菜单【View | Debug Window | Watches】菜单项打开Watch List窗口。

Note

将Watch List窗口泊位到Code Editor窗口的底部,这样,在调试代码时,总可以看到它。

在某些情况下,Watch List中变量的后面会显示一条消息,而不是该变量的值。例如,如果一个变量不在作用域之外,或未找到,Watch List在该变量名后面显示“Undeclared identifier: ‘X’”;如果程序没有运行或不停在断点处,Watch List在所有的监视项后都显示[process not accessible]。禁用监视项后显示<disabled>。根据应用程序的当前状态或某个变量的当前状态,还可能显示其他消息。

就像上一章提到过的,用户在Watch List中偶尔会看到这样的显示:variable 'X' inaccessible here due to optimization,这是带优化功能的编辑器的一个小缺点。如果要检查易被优化的变量,则必须关闭编译器的优化功能,即把Project Options对话框中的Compiler页面上的Optimization选项关闭。

未被初始化的变量会显示随机值,直到它被初始化。

Note

Watch List可用作一个简单的十进制/十六进制转换器。要把一个十六进制数转换成十进制数,可从主菜单选择【Run | Add Watch】,在Expression字段输入十六进制数后点击OK,输入的十六进制数和与之等价的十进制数就会显示在Watch List中;要将一个十进制数转换成十六进制数,除点击Hexadecimal单选钮将显示类型改为十六进制外,其余操作都与前面相同。由于Expression接受数学表达式,因此还可以把Watch List当做一个十六进制计算器,甚至可以在同一个表达式中同时使用十六进制和十进制值。如下图:

这样使用Watch List只有一个缺点,应用程序必须停在一个断点处

在调试应用程序的过程中,Watch List是一个简单而又关键的工作。为了说明Watch List的使用,接下来做一个练习:

1)创建一个应用程序,在其主窗体上放置一个按钮。将按钮的Name属性设置为WatchBtn,Caption属性改为Watch Test。将主窗体Name属性改为DebugMain,Caption属性改为Debug Watch List Test。

2)双击按钮,会在Code Editor中显示按钮的OnClick处理事件,按下面的样子修改其OnClick处理程序:

procedure TDebugMain.WatchBtnClick(Sender: TObject);
varS: string;X, Y: Integer;
beginX := Width;S := IntToStr(X);Y := Height;X := X * Y;S := IntToStr(X);X := X div Y;S := IntToStr(X);Width := X;Height := Y;
end;

3)保存该工程,将单元命名为DbgMain,工程命名为DebugTest。

4)在OnClick处理程序的begin语句之后的第一行上设置一个断点,运行该应用程序。

5)点击Watch Test按钮,调试器会停止在断点处。当调试器停在断点处时,IDE和Code Editor会显示在最顶层。

6)把变量S,X和Y增加到Watch List中(由于代码优化,变量X和变量Y在开始时是不可访问的),如下图:

7)安排好Watch List和Code Editor的位置,以便用户能同时看到两个窗口(不妨把Watch List泊位到Code Editor的底部)。

8)将输入焦点切换到Code Editor,并按F8执行下一行代码,执行完毕后,执行点移到下一行。此时Watch List中变量X显示一个值。如下图:

9)按F8继续一行一行执行程序,监视Watch List中变量的结果。

10)当执行点到达OnClick处理程序的最后一行时,点击工具栏中的Run按钮继续运行应用程序。

用户可反复点击Watch Test按钮来体会Watch List是如何工作的,每次还可试验不同监视设置的效果。

Note

在上面的例子中,OnClick处理程序先获取主窗体的Width属性和Height属性的值,接着执行一些计算,然后再将Width和Height设置成开始时的值。这段程序执行完后,什么都未发生改变。在该方法末尾给Width和Height属性赋值是有原因的。

如果在代码中不真正使用变量X和Y的话,用户就不能检查这两个变量,因为编译器在优化代码时会发现这个两个变量未被使用,从而将它们删除。在方法的末尾使用这两个变量就是为了避免编译器把它们优化掉。

前面提到过这个问题,希望大家对带优化功能的编译器的工作过程有个基本了解。这样,当开始调试应用程序,碰到诸如“Variable ‘Y’ inaccessible here due to optimization”一类的消息时就不会不知所措。

以上代码均在Delphi7中测试通过,实例代码下载:WatchList测试程序.rar

Delphi应用程序的调试(三)监视变量相关推荐

  1. c语言程序跟踪调试,VC6断点调试之监视变量

    上两讲中,为大家介绍到了VC6编译器的断点调试技巧,教给大家如何设置\取消断点.单步和跟踪一个程序.让大家具备基本的调试一个程序的能力.今天我们将继续深入研究教大家如何更细致.深入的跟踪和分析一个C程 ...

  2. Delphi应用程序的调试(二)使用断点

    Delphi应用程序的调试(二)使用断点 使用断点(Using Breakpoints) 当用户从Delphi IDE 运行程序时,程序全速运行,只会在设置了断点的地方停住. New Term 断点( ...

  3. Delphi应用程序的调试(十)调试器选项

    可在两个级别上设置调试选项:工程级和环境级.在前面的讲解中讲解了工程级调试选项,通过主菜单[Project | Options-]打开如下对话框: 可在Debugger Options对话框中设置全局 ...

  4. Delphi应用程序的调试(四)The Debug Inspector

    调试检查器(The Debug Inspector) Debug Inspector使用户能查看诸如类和记录的数据对象,也可以用它来查看整数.字符数组等简单数据类型,但这类简单数据类型最好是用Watc ...

  5. 【软件开发底层知识修炼】十六 快速学习GDB调试三 使用GDB的数据断点监测变量是否改变

    上一篇文章我们学习了如何使用GDB进行软件断点调试和硬件断点调试:[软件开发底层知识修炼]十五 快速学习GDB调试二 使用GDB进行断点调试 本篇文章继续上一篇文章的学习,如何使用GDB的数据断点监测 ...

  6. vba 修改文本文档 指定行_VBA程序报错,用调试三法宝,bug不存在的

    如果把VBA比作一门刀法,那么经过前面内容的操练,大家已经掌握了很多实用的招式. 如果我们在刀法招式的基础之上,再掌握更多的"磨刀"心法,那么我们的刀用起来才会又好又快. 所以今天 ...

  7. datagrid不显示 easy_VBA程序报错,用调试三法宝,bug不存在的

    如果把VBA比作一门刀法,那么经过前面内容的操练,大家已经掌握了很多实用的招式. 如果我们在刀法招式的基础之上,再掌握更多的"磨刀"心法,那么我们的刀用起来才会又好又快. 所以今天 ...

  8. c语言不用第三个变量 实现两个数的对调,下面程序功能是不用第三个变量,实现两个数对调操作 ....docx...

    下面程序功能是不用第三个变量,实现两个数对调操作 ... [3.1]下面程序的功能是不用第三个变量,实现两个数的对调操作.#include main(){ int a,b:scanf("%d ...

  9. 微信小程序开发系列教程三:微信小程序的调试方法

    微信小程序开发系列教程 微信小程序开发系列一:微信小程序的申请和开发环境的搭建 微信小程序开发系列二:微信小程序的视图设计 这个教程的前两篇文章,介绍了如何用下图所示的微信开发者工具自动生成一个Hel ...

最新文章

  1. Android 自定义百分比视图
  2. 【IOC 控制反转】Android 布局依赖注入 ( 布局依赖注入步骤 | 布局依赖注入代码示例 )
  3. HTML5中的CSS Shader技术
  4. oracle 数据回滚,恢复误删的数据,闪回表功能的使用
  5. Java 学习之网络编程案例
  6. 机器学习小技巧:模型训练完成后发送邮件
  7. js 实现2的n次方计算函数_「计算机组成原理」:一文快速了解计算机原理知识点-附思维导图...
  8. minute教会你shell
  9. [css]怎么改变选中文本的文字颜色和背景色?
  10. 在iOS设备上如何使用Chrome浏览器的书签
  11. python中codecs_Python:如何使用codecs模块将unicode数据保存成gbk格式
  12. 学php应该怎么学习数学,数学是怎样学好的 零基础怎么自学数学
  13. Android 系统(268)---native保活5.0以下方案推演过程以及代码详述
  14. 图解TCPIP-HTTP
  15. Oozie分布式任务的工作流——Sqoop篇
  16. 注塑机摆放间距多少合适_请查阅:过滤毛刷摆放参考标准!
  17. iOS app启动图片及icon图片及应用名设置
  18. gns3虚拟机服务器集群,GNS3中如何实现与Vmware Workstation连接
  19. adb interface 驱动问题(保证解决)
  20. Linux 系统中的用户管理

热门文章

  1. Composer帮你轻松管理PHP包 autoload
  2. [note]抽象类和接口的相同点和不同点
  3. Oracle 日常开发记录
  4. Tomcat 服务器介绍和使用
  5. Inversion of Control(控制反转)之 Dependency Injection(依赖注入)
  6. 汉诺塔的递归实现,看完就懂了
  7. php一对一模型关联,通过实例学习Laravel模型中的一对一关联关系
  8. 四元数组旋转_四元数应用——顺序无关的旋转混合
  9. [Learn Notes] CSS学习笔记
  10. Spring核心系列之ApplicationContext