把握C++ builder的除错艺术(2).1
副标题#e#
第二篇-近间隔调查(1)
1.调试可执行措施前的筹备
2.工程选项
3.配置断点并冲入可执行措施
4.察看储存在变量中的值
5.利用Watches(调查)
6.利用Inspectors(巡视器)
7.利用Evaluate/Modify(求值/修改)
8.Stepping Through, Over and Around Blocks of Code
9.Stepping的范例
10.Stepping的注解
11.其他提示
Okay,(再小小筹备一下)此刻开始追踪、搜索颠末前次的尽力后仍然躲在代码中的bug的时候了,也就是开始跟踪前一篇文章代码里标志过的bug/异常。首先是筹备阶段。
调试可执行措施前的筹备
在我们开始调试可执行措施前,我们需要确保一些配置在大大都环境下的正确性。我将会一条接一条的过一遍,并简朴表明一下为什么必需那样做。(假如您对有些对象感乐趣的话,按下辅佐按钮,会有很多更详尽的内容)。此刻就开始吧,先打开Project|Options选项。
工程选项
首先我们在"Compiler"(编译)标签处停下。您只需简朴的单击"Full debug"(完全调试模式)按钮,我们所需的绝大大都的其余配置就已经搞定了。将"Code optimization"(代码优化)设为"None"(无)老是件功德,这样做实际上汇报编译器:所有的工作都已做好,只需产朝气器码就行了。而不要为了提高一点点运行速度实验举办其他的智能优化。(虽然,一切都完成之后,您可以打开此项。)这样做的长处是大大低落了我们调试的难度。因为措施中的代码与我们书写的一样,没有被编译器优化过。在"debugging"(调试)面板中,将"Debug information"(调试信息)选上(点一下),而且必需配置为"Line number information"(行数信息)。我还发起将"Disable inline expansions"(禁用内联扩展)一项选上。内联扩展对宣布的代码来说很好,但调试时最好照旧关掉此项,他只会让您更头痛。
然后是"Pascal"标签,尤其在您的工程里毗连了Pascal单位或利用了基于Pascal的VCL控件时(若您拥有其Pascal源码时,编译器会自动利用此节中的配置从头编译)。这里您必需将"Optimization"优化选项禁用,然后凡是我会将"debugging"(调试)部门的所有选项选上(打钩)。
接下来是"Linker"(链接)标签,我们需要选上"Create debug information"(生成调试信息)。"Use dynamic RTL"(利用动态RTL)以及"Don’t generate state files"(不要生成状态文件)是造成贫苦的选项。我凡是城市利用状态文件(这样答允增量链接,但会在编译目次下发生一个4倍于可执行措施或更大的文件),换个角度来说,这样会增加链接大工程时的速度。而利用dynamic RTL自己就是个争论,另有许多附和和阻挡的接头。
下一个是"Directories/Conditionals"(路径/条件)标签。在这里我们想要设定"Directories/Conditionals"(调试源路径)的值。我们永远都应将此处设定为$(BCB)\source\vcl,可是假如您有任何其他的组件附加的话,凡是将它们的路径也加上是个好主意(路径与路径之间用”;”脱离可能您可以用按下…按钮弹出的对话框来设定它们)。
最后也是最重要的配置是在"Packages"(措施包)标签上。按照所有恰如其分的调试履历您必需禁用"Build with runtime packages"(带运行时措施包编译)。这么做的原因是措施包自己不包括并且不能包括调试信息。这样做,也许倒霉于您跟踪尺度的VCL代码,譬喻想看清楚VCL函数y中参数x是如何起浸染的时候。可是大大都时候,您这么做将会发明调试器将您的绝大大都“症状”归结给VCL,尽量“病因”就在您的源代码中(或在其他的组件中(这已经在我们所有人身上产生了))。一旦您宣布您的正式版本时,您可以抉择是否利用措施包。(译者注:措施包的本质是一个非凡的DLL,不带运行措施包(静态)编译可以让您的措施离开Cbuilder独立运行。),但在调试时,请禁用掉。按下OK按钮,我们已经筹备好啦。下一个对话框只需打开一次,但最好照旧来查抄以下我们在这里的设定是否正确。好了,打开”Tools|Debugger Options…”吧。
对话框最下方的"Integrated debugging"(集成调试器)选项是要害地址。确信已经打上钩。按下OK按钮筹备编译可执行措施吧。我发起从头来一次彻底的编译(选择Project|Build All),假如您修悔改您的配置的话(尤其是改变”building with packages”方法后)。这将担保我们的所有措施单位凭据我们所但愿的那样被编译。
配置断点并冲入可执行措施
#p#分页标题#e#
象您所见过的其他任何一款调试器一样,C++Builder提供强大的断点配置成果。根基上,断点是指代码中的一个点,措施执行至此停下(与退出差异,这只是执行中的暂停)并将节制权交还给调试器。配置一个断点相当容易。只需在您想要配置的措施代码行左侧的灰色槽形区域点击,您会看到一个红点呈现,这一行也会变红。措施运行到这一点就会暂停,将节制权交还给调试器。
您也许会问假如我不想每次都停下来呢?虽然可以,并且还很容易做到,这取决于您暂停措施的尺度是什么?(译者注:条件断点)。在适才谁人断点(红点)上右击鼠标并从弹出菜单上选择” Breakpoint Properties”(断点属性)。此处可以设定两种属性"Condition"(条件)和"Pass Count"(通过次数)。Condition(条件)属性太利便了。您可以操作if()语句输入险些是任意的条件。但请紧记条件中的所有变量,对此断点都应是可见的。条件属性并未被编译器编译到执行措施中,而是在运行时,当措施运行至断点暂停后,查抄断点的条件是否满意。条件为真,停下,不然让措施继承运行。另一个属性"Pass Count"(通过次数)也很容易领略。断点将被通过Pass Count次后停下。团结利用这两个属性,在调试您的代码时,您可以设定很是严格的断点。
尚有一件要紧记的是,当您在调试器中产生异常时,会以发生异常处的那一行代码上的断点的形式呈现。这种环境很容易制造。一旦您获得一个异常后应做的步调我会在今后展示如安在仓库中回溯并跟踪找出异常产生的真正原因(如引起异常发生的那一小片代码)。
另一个要紧记的提示是当您运行您的措施时,代码窗口左侧有蓝点的任意一行都可以设成断点。所有犯科的断点将会变为红点中带一个黄色的小叉,这一行代码也会酿成黄褐色。正当的断点则变为红点中带一个绿色的小钩。运行时,您可以配置/修改任意一点,断点当即生效而无须从头编译。
#p#副标题#e#
察看储存在变量中的值
一旦您的措施在您的断点处停下后,该做什么?有一件事您想做并且必需做的,那就是察看储存在您措施中的各类变量真实的值。这部门内容涉及的方面许多,您必然要僵持,忍受这些枯燥的对象。幸运的是当您看完这些,您必然会对换试器这部门最强大的成果有些新的领略。有很多种要领可以察看变量的值,主要要按照您的目标来抉择。我会从察看当前函数的Local Variables(局部变量)开始把他们都讲完。
察看局部变量没有太多可以讲的。只需点击”View|Debug Windows|Local Variables”,或按下ctrl-alt-L将会弹出一个窗口,显示了当前函数的局部变量。窗口中的变量将会随您单步向下执行或回溯的函数体的更新而更新。
利用Watches(调查)
下一步您可以通过设定一个variable watch(变量调查)来察看措施中的变量。就象它的名称所表达的,调查一个变量并将其值显示在变量调查窗口中(点击"View|Debug Windows|Watches"或按下 ctrl-alt-W)。您可以通过两个途径来添加一个调查,第一种是在代码窗口中高亮选择您要调查的变量或表达式(是的!它可以领略并对绝大大都简朴表达式求值,好比(i*j)+05 可能 SomeVector[i].Name)并右击鼠标,选择"Debug|Add Watch at Cursor"或按下ctrl-f5,就会插手调查窗口。假如须要,同时会打开调查窗口
您还可以通过在调查窗口的空缺处双击来添加。这时会弹出添加watch对话框,"Expression"(表达式)域的意思无须多说,但另几个域我想表明一下,它们也同样利便。
"Repeat count"(反复值)用于您调查一个已知长度的数组变量(好比一个blah[50]数组)。您要将Expression(表达式)设为数组的名字(本例中是blah)。"Repeat count"设为数组的元素数量(本例中是50)。然后就会显示数组的每个元素(如:blah[0], blah[1], blah[2]…)。
"Digits"(小数位数)用来设定显示十进制浮点数的小数位数的。下面的点选荟萃是用来强制设定变量的显示范例的(将无标记长整数显示为十六进制名目)。尚有一点要出格说明的是,假如您在watch窗口顶用鼠标右击一个watch后的弹出菜单上会呈现"Break When Changed"的选项,这将在变量上设定一个断点,在此变量产生变革时会暂停措施。
利用Inspectors(巡视器)
巡视变量是察看变量中的数据的第三种步伐。也险些是调查完整的类的数据的最佳要领。可以有两种要领来巡视一个变量。第一种是在local variable window(局部变量窗口)中,双击一个变量,将会弹出"Debug Inspector"(调试巡视器)窗口,内里显示了这个变量所有的"Data" (variables) (数据(变量))、"Methods" (functions)(要领(函数))和"Properties"(属性)。假如这是个简朴数据,将会显示此变量的名称及个中的值。(译者注:假如是数组呢?真不错!)
#p#分页标题#e#
您会留意到,Debug Inspector(调试巡视器)很象property editor(属性编辑器)。虽然如此,越发重要的是,事实上您可以在运行时及时改变这些值!!!小心利用啦!改入坏值的功效会让您有说不出来的悲哀。巡视器的这个本领可用来快速测试(假设的)游戏关卡(译者注:仿佛FPE,GM),而不消有编译-运行-修改-编译-运行的轮回。
(举例巡视Form1)在properties(属性)页上,您将会看到某些属性实际上并没有显示其的值,而是显示了{read=,write=}。假如这些值可以被赋值的话,当您在此区域单击后,您会留意到一个"?"按钮呈此刻属性的右侧。单击这个按钮将会系统执行适当的函数来实验取回属性的值。我们可以在这儿举个例子-就举Form1的MDIChildCount的属性吧。在MDIChildCoun的属性值区域上单击,在按下"?"按钮,哇,0(正长短-MDI的措施的指定值)。调试巡视器强大的本领并未到此为止。在巡视器的成员变量的适当区域双击可以打开成员变量的巡视窗口,提供与您开始打开窗口一样的本领。
巡视器窗口的另一个有用的成果是从工具担任的本领。这可以在通过在适当区域上右击选择"Descend"(担任)来做到。担任的功效是发生了一个新的变量。您会留意到顶部的下拉List box中的变量名称已经换成新的变量名了。您可以直接在ListBox中切换巡视的变量。这使得在工具的差异部门快速切换变得很是简朴,而不会让大巨细小的巡视器窗口扰乱您的事情空间。
有一点要紧记的是,假如您分开函数,可能分开变量的浸染范畴,调试巡视器会失去对变量的跟踪。若您需要再次察看的话,请从头配置巡视器。可是您在当前函数的代码中单步运行的话,巡视器会自动刷新。