Mastering the Art of Debugging in C++Builder
Article 2 - Watching it Closely
掌握C++Builder的除错艺术
第二篇-近距离观察
(2)
使用Evaluate/Modify(求值/修改)
最后一种显示变量或代码块的值的途径是Evaluate/Modify(求值/修改)窗口。这个窗口可以象打开巡视器一样打开,在您要Evaluate/Modify(求值/修改)的代码行上右击选择"Debug|Evaluate/Modify"就会弹出Evaluate/Modify(求值/修改)窗口。本窗口用来对表达式/变量求值并/或修改。Watches和/或inspectors也可以实现同样的功能。但如果您想要修改的话,这里恐怕是最好的地方。
“察看变量已经听够了,现在我想去看看我的代码到底怎么了,而不是干坐在这里。”我听见您如是说。下一节我们将在函数体内外单步跟踪直至断点(还记得前面的东西么?)。
在代码块内外进行Stepping(单步执行/跟踪)
在此有一件事要牢记,前面讲的绝大多数察看变量的办法是动态更新的。所以当您跟踪至新的一行的时候,变量的值会被自动重新求值,并且显示在窗口中的值被更新成新的当前值。
Okay,当您点击您所设置的断点时,您会看到您所需检查的变量。下一步就是在代码中单步执行并且近距离观察实际发生的与您所猜测的是否一致(通过使用watches/inspectors并跟随代码的执行路径前进)。
Stepping的类型
这部分解释起来似乎很简单。但下面的大部分都是来讨论您用这些能做什么(好像在别处没有听到过?)。您可以告诉调试器五种"stepping types"(单步执行类型)。我们会按Run菜单上的顺序来解释。我同时会给出它们的快捷键。在调试时使用快捷键的次数会多过使用菜单选项的(比较按10次键盘与选10次菜单,我想您知道什么更好)。
第一种是"Step Over"(在函数体外单步执行)或者f8。这会让调试器执行代码至当前函数的下一行可见的代码停下,或者当运行至当前函数的最后一行时,调试器返回至调用函数停下。在您知道所调用的函数没有问题时,stepping over功能很方便。
下一个是"Trace Into"(跟踪至函数体内)或f7。如果运行的当前行是调用一个函数,调试器将把我们带到调用的函数的第一行(即使是隐含调用函数,例如一个write属性)。否则执行至当前行的下一行。当您想看看这个函数到底做些什么时,这个功能非常方便。
接下来是"Trace to Next Source Line"(跟踪至下一个源代码行)或shift-f7。调试器会运行至下一个具有调试信息的代码行。这与"Trace Into"的区别,让我们举例来说明吧。当我们调用一个没有源代码的windows API函数并且这个API函数调用了我们代码中的一个回调函数。"Trace to Next Source Line"将在回调函数的第一行停下来,而"Trace Into"会忽略这个回调函数并在当前程序的下一行停下来。
然后是"Run to Cursor"(运行至光标处)或f4。调试器将运行代码直至光标所在的行。这使得不需设置断点又可以跳过大片代码变得很方便(考虑只需停顿一次的情况)。
还有"Run until Return"(运行至返回)或shift-f8。调试器将运行代码直至当前函数返回调用他的函数。当您不想手工单步执行至函数结束(假如您陷入一个循环中的话,这个过程会变的十分冗长)时,这么做就会很方便的跳到函数的结尾处。
最后一个是"Program Reset"(程序重置)或ctrl-f2。调试器会中断已运行的程序并返回至调试器。除非迫不得已不要这么做,因为对象所使用的资源没有被释放!!!(在一个数据库应用程序中,这样做2-3次后,您将不得不关闭并重启IDE,因为BDE内部资源将耗尽。您已经被警告啦)。当您不得不中止可执行程序时,这非常有用。
最后(却在菜单很上面的位置)是"Run"(运行)或f9。调试器将运行至程序结束,除非碰到您点击新的断点或发生异常。
Stepping的注解
要牢记的是所有这些单步执行方式在调试器通过断点时,调试器会对断点求值,若断点需要就停下。如果出现异常,调试器也会停下。
正如您所见,在正确的地方设置断点,察看变量并在代码中单步跟踪,我们能够以非常近的距离观察程序在做什么就好象它真的运行一样。这些功能在追查最困难的bugs---逻辑bug时,相当方便。
其他提示
如果您真的很勇猛并有汇编语言的经验,您可以点击"View|Debug Windows|Cpu"打开一个"cpu view"CPU窗口。这里不仅显示了当前可执行程序的指令的汇编指令,还有象CPU标志、寄存器的内容和不断更新的内存印象
使用Call Stack ("View|Debug Windows|Call Stack")可以很方便的找出发生异常之前或遇到断点之前的函数调用历史。记住,这里只是显示什么函数被什么函数调用过,并非真正的调用过程的历史记录。因此,这个窗口可能先会让您感到困惑。但是只要开着它来stepping through单步跟踪代码至函数体内,好好观察一下您就会完全明白了。
C++BUILDER4、5中,watch, local variable, 和 call stack窗口可以驻留在code主窗口中,使用起来更加方便。C++BUILDER5中还可以设定调试布局,以便在调试时使用(针对您在设计时使用的设计布局来讲的)。
使用所有我所公布的所有技术再加上一点点耐心和一双火眼金睛,您应该可以解决99%的bug。若您想找到bug,耐心是必要的。花点时间,深呼吸一下,不要让挫折吓倒。如果有必要,走出去5分钟干点别的,您会惊奇的发现自己有了新的视野或者发现开始时漏掉了什么步骤。
如果您有其他的技巧和提示觉得应该加入此文,请尽管来信告诉我们,我们会在以后的版本中加入您的意见。
好了,我希望这篇文章在某种程度上有助于耐心的读者们。如果正是这样,我会十分高兴自己干了件不错的工作。也许您所有的bugs都已微不足道了。
原著:Bill King
翻译:史平洋 - CKER
版权说明:
国内的网站上,有许多关于C++Builder的内容,但多以软件、组件为主。论坛里也大都不能令人满意,很空虚的感觉。书籍又都昂贵,内容却有抢钱之嫌。对银子不足的初学者、自学者关爱不够,因而想尽自己的绵薄之力。
文中的所有资料都是从国外网站上收集而来。因为E文不方便,所以翻成中文。因为English和计算机都不是非常好,文中的错误在所难免。若大家觉得有用的话,我计划不断搜集翻译一些有用的东西。
有任何意见和建议请mailto:cker@sina.com
您可以随意复制、分发、下载此文档。但未经本人同意,您不可以截取、改动本文片断,或用本文谋取任何形式的利益。
史平洋
2001.2