一、准备调试
Delphi 在 IDE 内部集成了一个调试器,因而对程序的调试不用离开集成开发环境(IDE)就可以进行。该调试器能够控制程序的运行、监视程序的输出、检查和修改变量的值。
在调试程序之前,必须保证程序代码已经没有语法错误,还要正确设置一些选项。为此,需要使用【Project】菜单中的【Options】命令打开【Project Options】对话框。
打开【Compiler】对话框,选中【Debug information】复选框(默认为选中)。这样,编译器将把 所有的调试信息加到.dcu 文件和.exe 文件中。
VCL 的代码都是仔细调试过的,一般不会有错误。如果仍然不放心,想跟踪进入VCL的内部,则需要选中【Use Debug DCUs】复选框。 要说明的是,调试信息将使可执行文件增大,但不影响程序的性能和对内存的需求。
尽管如此,调试结束后,最好要打开【Project Options】对话框,在【Compiler】选项卡中,清除【Debug information】复选框,再重新编译程序。这样,程序中就不包含任何调试信息。要使用内部集成调试器来调试程序,还必须使用【Tools】菜单中的【Debugger Options】 命令打开【Debugger Options】对话框,选中【Integrateddebugging】
复选框(默认为选中)。否则,【Run】菜单中的调试命令将变灰。但要说明的是,内部集成的调试器可能会与某 些软件冲突,从而引起应用程序运行异常。因此,在调试程序时最好把可能引起冲突的软 件退出运行。
使用【Tools】菜单上的【Environment Options】命令打开【Environment Options】对话框,再打开【Preferences】选项卡。如果选中【Hidedesigners on run】复选框,当程序运行 时,【ObjectInspector】和【Form】设计器将关闭,以腾出屏幕上的空间。如果选中【Minimizeon run】复选框,当程序运行时,IDE 将最小化,以避免屏幕上内容太多太乱。不过,当程 序暂停运行时,IDE 的窗口会重新恢复成原始大小。
二、设置调试器的选项
1. 设置调试器选项
要设置调试器的选项,可以使用【Tools】菜单中的【Debugger Options】命令打开
【DebuggerOptions】对话框,如图 7.2 所示。在其中的【General】选项卡、【Event Log】 选项卡、【Language Exceptions】选项卡和【OS Exceptions】选项卡中,可以设置调试的一 些环境、配置及方法等。
2. 编译指令
图 7.2 【Debugger Options】对话框
默认情况下,上述设置对整个项目的所有单元都有效。不过,也可以让这些设置只对部分单元有效,因为有些单元可能没有问题,不需要调试。
要使某个单元不包含调试信息,就在这些单元中加入适当的编译指令,例如:
unit Unit1;
{$DEBUGINFO OFF}
interface
…
3. 自定义调试器的颜色
在前面已提到,代码编辑器可以用不同的颜色显示不同的语法成分,在使用调试器调试程序时也有这个功能。例如,通常断点用白底红色表示,当前执行点用白底蓝色表示。 要自定义调试器的颜色,可以使用【Tools】菜单上的【Editor Options】命令打开【Editor Properties】对话框,再打开【Colors】选项卡,在【Element】框中选择某种语法元素,然后设置它的前景颜色和背景颜色。
三、控制程序的运行
3.1单步执行
当调试信息编译了程序后,就可以调试程序了,调试器将接管对程序运行的控制,但 程序的运行结果与在非调试状态下运行没有什么两样,包括建立窗口、接受用户输入、计算数值、响应事件、访问数据库等均照常进行。
通过【Run】菜单中的【Step Over】命令,可以单步执行程序。所谓单步执行,就是 一次只执行一行(一个指令),这样就可以知道哪一行或指令引起了运行期错误或逻辑错误。
【StepOver】命令将把整个过程或函数当做一行。如果把几条语句写在一行上,调试 器将把这几条语句当做一条语句。这样,就无法单独调试其中的某一个语句。如果把一条长语句分成几行写,调试器仍然把这几行当做一行。
调试器每执行一行,当前执行点就自动移到下一个要执行的行上,但不一定是源代码的下一行。例如,若正在执行的是 goto 语句,当前执行点将移到 goto 语句跳转到的行上。
另外还有一种情况就是,如果开启了优化编译的选项,某些源代码行将被合并或越过,这时候,当前执行点不会移到这些行上。
为了清晰地看出当前执行点在哪儿,代码编辑器将用白底蓝色显示当前执行点,同时,在“装订区”显示一个绿色的箭头指向当前执行点,如图 7.3 所示。
图 7.3 当前执行点
3.2跟踪执行
【Run】菜单中的【Trace Into】命令用于跟踪程序。与单步执行相似,这条命令一次 也只执行一行。不同的是,执行到有函数调用的行时,这条命令将进入函数的内部。
如果程序链接了外部代码诸如动态链接库,只要动态链接库包含了符号调试信息,就 可以跟踪进入这些外部代码。否则,调试器将把动态链接库当做一行处理。
在调试过程中,可以根据需要交替使用单步执行和跟踪执行。例如,对有疑问的调用 命令使用跟踪执行,使控制进入被调用部分内部,调试该被调用部分。而对有把握的调用命令使用单步执行,从而直接跳过被调用部分的调试,这样能提高调试效率。
【Trace Into】命令也能够进入事件句柄的内部,就像进入一般的函数内部一样。要注 意的是,OnPaint 事件是当应用程序的窗口需要重画的时候触发的,当进入处理该事件的句 柄内部时,代码编辑器的窗口将推到前端。也就是说,此时窗口需要重画了,这样又将触发 OnPaint 事件。而一旦进入处理 OnPaint 事件的句柄内部,代码编辑器的窗口又将被推到 前端。如此反复,构成无限循环。要解决上述问题,必须把代码编辑器与应用程序的窗口在屏幕上重新排列,不要相互覆盖。
程序往往大量调用了 VCL 的方法,一般情况下,不要跟踪进入VCL 的内部,因为 VCL
的源代码一般是不会出错的。如果怀疑 VCL 中可能出错,或者想进入 VCL 方法的内部看 看方法是怎样实现的,也可以进入 VCL 方法的内部。Delphi Enterprise 和 Delphi Professional 附带了 VCL 的源代码,而且还提供了带调试信息的 VCL 库。
3.3 跳过一段代码
为了节省时间和提高工作效率,不必每次都从头开始单步或跟踪执行程序,可以直接 跳到有疑问的地方,然后再一行一行地执行程序。
【Run】菜单中的【Run to Cursor】命令可以实现这个功能。它能够先以非调试方式执 行到光标所在的行,再接管对程序的控制,单步或跟踪执行以后的代码。
如果光标所在的行不包含调试信息,调试器将弹出一个错误框显示“No code wasgenerated for the current Line”。
如果不小心进入了例程的内部,想马上退出来,可以把光标移到该例程的最后一行,使用【Run to Cursor】命令,再使用【Step Over】命令,就可以返回到调用该例程的地方。
3.4 全速执行剩余的代码
如果不小心进入了一个例程,但又不想调试这个例程,或者确信该例程的代码没有问题,从而想尽快退出这个例程,可以使用【Run】菜单中的【Run Until Return】命令。这个命令将全速执行该例程的代码,直到返回为止。
3.5 返回到执行点
在调试过程中,随时可以切换到 IDE 或其他程序中,进行各种操作。如果要重新回到调试器的当前执行点,可以使用【Run】菜单中的【Show Execution
Point】命令,光标将自动回到先前的执行点上。 如果包含执行点的源文件已关闭,调试器将重新打开这个源文件。如果执行点没有对
应的源代码,Delphi 将打开 CPU窗口,显示相应的机器指令。
3.6 暂停运行
使用【Run】菜单中的【Program Pause】命令将使程序运行暂时停止,这样就可以检 查程序在此状态下的输出或变量的值是否正确,检查完以后,可以继续对程序进行调试, 或者修改变量的值再让程序继续执行,以便看程序对新的值会做出什么反应。
有时候,程序暂停后无法回到调试器中继续运行,这时候可以同时按— 下
Ctrl+Alt+SysRq键终止程序的运行,如果按一次无效,就多按几次。
3.7 重新开始运行
在调试过程中,可以使用【Run】菜单中的【Program Reset】命令中止程序的运行并释 放所有占用的内存和资源,关闭所有打开的文件,清除所有的变量设置,然后重新运行程 序。这通常用于在调试过程中发现了错误并更改了源代码后需要重新编译和运行的情况。
【Program Reset】命令并不删除先前设置的断点和观察表达式,因为重新开始调试程 序时可能还要用到这些设置。
【Program Reset】命令可能不能很“干净”地释放应用程序占用的所有资源,这样可 能导致其他程序运行失败,碰到这种情形应当退出 Delphi 或者重新启动 Windows。
3.8 命令行参数
如果要调试的程序需要传递参数,可以使用【Run】菜单中的【Parameters】命令打开
【Run Parameters】对话框,如图 7.4 所示。
图 7.4 命令行参数
在【Parameters】框内键入要传递的参数,也可以从以前键入过的参数中选择一个。