主页C++ Builder 资料C++ Builder 操作指南编译、运行和调试程序调试 exe 项目
C++ Builder 串口控件
C++ Builder 编程技巧
C++ Builder 操作指南
IDE外观和窗口布局方案
欢迎页面
创建和管理项目
创建和管理项目组
编译、运行和调试程序
 • 编译 Make/Build
 • 运行 exe 项目
 • 调试 exe 项目
 • 调试库 .dll .a .lib 或控件 .bpl 项目
项目的常用的重要配置
窗口画面编辑
有多个窗口的程序
程序的显示主题/切换皮肤
编辑程序代码
安装第三方控件/组件包
快捷键大全
IDE或编译器出错处理
C++ Builder 参考手册
网友留言/技术支持
调试 exe 项目 - 编译、运行和调试程序
 • 断点、单步运行
  ◦ 设置和取消断点
  ◦ 有效的断点,无效的断点,禁用的断点
  ◦ 查看和管理断点列表
  ◦ 单步运行
  ◦ 查看和调试 CPU 反汇编代码
  ◦ 查看断点或单步运行时的变量的值
   · 鼠标悬停
   · Local Variables
   · Watch List
 • 输出信息到 C++ Builder 的 Event Log 区域
 • 使用日志文件
 • 使用 CodeGuard

断点、单步运行

调试程序,最常用的方法是使用断点和单步运行,需要这个项目:
 • 选择 Debug 方式编译
 • 使用调试方式运行

设置和取消断点

 • 点击要设置或取消断点的那一行程序上,按键盘的 F5 键设置或取消这行代码的断点
 • 用鼠标点击程序代码行号左面的空白区域,也会设置和取消这行代码的断点

如果这行代码有断点,会在行号的左面,就是上面截图的位置,有红色的圆点作为断点标识。
程序在调试方式运行的时候,运行到这句代码的时候,会停下来,能看到此时变量的值

有效的断点,无效的断点,禁用的断点

点击工具条上的 “” 或者按 F9 运行,下面是断点位置的截图:

无效的断点
当前运行到这,停在了这个断点上
这个位置没有断点,但是可以设断点的代码
有效的断点

无效的断点的原因是,这个位置没有程序代码,例如空行或注释,或者没有编译生成可执行的代码,例如定义变量。上面截图的无效断点就是只定义了变量,没有可执行的代码。

禁用断点:在断点列表里面禁用和启用断点。在断点列表里面还可以对断点进行设定进入断点的条件等。

查看和管理断点列表

 • 选择菜单 View → Debug Windows → Breakpoints
 • 使用快捷键 Ctrl + Alt + B

如下图,下面的 “Breakpoint List” 就是断点列表。

Filename/Address 文件名(源码断点) 或地址 (地址断点),旁边的对钩是启用/禁用断点。如果把对钩去掉,断点就被禁用了,对应于源码上的断点也相应变灰,例如上图的第 129 行代码的断点。
Line/Length 行号 (源码断点) 或字节数 (数据断点)。
Condition 在这个断点停下来的条件。如果这里为空,没有输入条件,每次执行到这里的时候都停下来。如果输入了条件,当这个条件为真的时候,停在这个断点上。如上图,条件为 “i==5” ,当 i 的值等于 5 的时候,停在了断点上。
Thread 有多个线程调用这段代码时,在以调试方式运行的时候,可以选择希望在哪个线程里面执行这段代码时,停在这个断点上,而不去理会其他线程是否执行了这段代码。
Action 断点执行的动作,一般都是 “Break”,即程序运行到这里停下来
Pass Count 程序运行时,经过这个断点的次数。这里输入一个整数值,是希望程序运行的时候,经过几次这个断点停下来。
如上图:第 133 行断点,输入了 8 ,即 8 次停下来。现在停下来的时候,是第 5 次,Pass Count 里面显示的 5 of 8,现在停下来的原因,是在第 132 行断点停下来了,那里设定的条件是 i==5。再继续运行,即点击 “” 按钮,或按 F9 执行,会在第 8 次经过这个断点的时候停下来,此时 Pass Count 里面显示的是 8 of 8,此时的 i 值是 7,i 值从 0 到 7 正好是 8 次。 如下图:停在了第8次经过断点的地方。
Group 给断点分组,在这里输入分组的名字,会创建一个新的分组,或者加入已有的分组。也可以在下拉表里面选择已有的分组。

在调试程序的时候,一般都使用源码断点,即在源程序上设定的断点。地址断点和数据断点在 “查看和调试 CPU 反汇编代码” 的时候使用。

 

单步运行

程序停在断点上的时候,可以进行单步运行。


调试程序的工具条

Step Over快捷键 F8,工具条上的 “” 按钮,或者选择菜单 Run → Step Over,执行当前这一句程序代码,停在下一句程序代码上
Trace Into快捷键 F7,工具条上的 “” 按钮,或者选择菜单 Run → Trace Into,执行当前这一句程序代码,如果这句代码是调用函数,那么会跟踪进入函数,停在函数里面的第一句代码上,如果这句代码不是调用函数,会和 Step Over 一样停在下一句代码上
Trace to Next Source Line快捷键 Shift + F7,或者选择菜单 Run → Trace to Next Source Line,执行当前的代码,停在对应于源程序代码的下一句代码上。这个功能也会跟踪进入函数,和Trace Into 的区别在下面的 “查看和调试 CPU 反汇编代码” 里面描述
Run to Cursor快捷键 F4,或者选择菜单 Run → Run to Cursor,继续执行程序代码,一直到光标位置,停在光标位置的代码上,光标位置的这句代码没有设断点也会停在这里。
Run Until Return 快捷键 Shift + F8,工具条上的 “” 按钮,或者选择菜单 Run → Run Until Return,执行当前函数里面的代码,一直到这个函数返回到调用位置,停在调用函数位置的下一句代码上
Program Pause工具条上的 “” 按钮,或者选择菜单 Run → Program Pause,程序暂停运行,停在正在执行的程序代码上,如果当前在库函数或Windows消息循环里面,没有源程序,会停在反汇编代码上
Program Reset 快捷键 Ctrl + F2,工具条上的 “” 按钮,或者选择菜单 Run → Program Reset,这是复位,程序停止运行
Run 快捷键 F9,工具条上的 “” 按钮,或者选择菜单 Run → Run,会继续执行,一直执行到停在下一个断点上。

 

查看和调试 CPU 反汇编代码

当程序运行停在了断点上,可以查看这个位置的反汇编代码,选择菜单 View → Debug Windows → CPU Windows → Disassembly,快捷键 Ctrl + Alt + D:

在上面截图里面可以看到,C/C++的程序代码的反汇编代码,每句 C/C++ 代码可能会对应一句或几句汇编代码。在 Disassembly 窗口里面,单步运行时:

Trace Into单步运行的时候,会执行一条汇编代码,停在下一句汇编代码上。如果是函数调用,会跟踪到函数里面,停在函数里面的第一条汇编代码上。如果调用的函数没有源程序,例如库函数或API函数,也会按照反汇编,停在这个函数的第一条反汇编代码上,如果继续跟踪,可能会跟踪很长时间都在库函数或API函数的源程序里面跑,这时候,如果再想跟踪回源代码位置,需要用Trace to Next Source Line停在下一句执行到的源程序代码上对应的反汇编上。
Trace to Next Source Line会执行一条或几条汇编代码,停在下一句 C/C++ 程序代码对应的第一条汇编代码上。如果有函数调用,并且调用的这个函数对应了 C/C++ 源程序,会停在函数里面第一条C/C++源程序对应的汇编代码上。有的函数是没有源程序的,例如库函数或 Windows API 函数等,如果没有源程序也会跟踪到函数里面,但是不停下来,会一直执行到找到源程序位置,比如这个函数有产生事件或调用 CALLBACK函数,也会停在事件或CALLBACK函数里面,停在执行到的下一条源程序代码对应的汇编代码上。
其他的 Stop Over、Run to Cursor、Run Until Return、Run等,都和前面调试 C/C++ 源程序代码的一样。

 

查看断点或单步运行时的变量的值

鼠标悬停

停在断点时,鼠标停留在变量上,可以看到变量的值,例如下面截图里面的 v 的值

Local Variables

在左面的 Local Variables 里面,能看到局部变量的值

Watch List

Watch List 除了可以查看变量值之外,还支持表达式,例如上面截图的 a + b,值为 5,数组的值,可以看到下面截图的 v,数组 v 的值可以点击 “+” 号查看更多的值。还有另外的查看数组的方法,可以设定查看数组里面某个值或某个值开始的几个值,例如下面截图的v[3]开始的2个值: 6 和 8。

在 Watch List 里面,点击鼠标右键,选择 Add Watch 添加

Expression变量或表达式
Group name显示在 Watch List 里面的分组名,可以自己随意取一个名字作为新的分组名,分组会显示在 Watch List 下面的分页卡上,用以切换显示的分组
Repeat count从表达式那个值开始,显示的值个数,一般都是数组使用,例如上面的截图里面,是显示从 v[3] 开始的2个值,即v[3] 和 v[4] 的值
Digits如果表达式的值是浮点数,这里是浮点数显示的位数
Enabled启用/禁用这个Watch值,打勾为启用
Use visualizer把不可读的变量值显示为可读的值,按照Embarcadero的文档提示,主要是影响日期和时间类型,如果这个不打勾,显示出来的值是一个浮点数,不知道具体表示的日期和时间是什么,如果打勾了,可以看到日期和时间的值,例如 “2016-05-06 16:25:32”。默认情况,这个是打勾的。
Allow side effects and function calls如果表达式里面包含函数调用, 是否调用函数去计算表达式的值。默认情况,这个是不打勾的,表达式需要调用函数才能计算出来的时候,显示的值会为无法计算。
下面有9个单选项是把变量或计算的值显示为什么样的类型,默认情况,选择Default会自动识别,多数情况不需要修改。

删除 Watch List 里面的表达式:鼠标右键点击到要删除的项目上,选择 Delete Watch。
修改 Watch List 里面的表达式:鼠标右键点击到要修改的项目上,选择 Edit Watch。

 

输出信息到 C++ Builder 的 Event Log 区域
函数 OutputDebugString(字符串); 可以把字符串输出到 Event Log 区域,只要执行到了这个函数就会输出,无论是 Debug 方式编译还是 Release 方式编译。

有时候不希望程序停下来,只是想看看程序是否执行到了代码的某个位置,或者想看看程序执行的流程顺序是否正确,可以用这个方法。

OutputDebugString 的参数是字符串,用起来不是很方便,可以做这样的一个定义:

#define TRACE(s...) OutputDebugString(String().sprintf(s).c_str())

这样,TRACE 就和 printf 的参数一样了,支持格式化输出到 Event Log 区域。

下面就是 TRACE 的例子和执行结果,TRACE 格式化输出到 Event Log 区域:

 

使用日志文件

写一个简单的写文件的函数,这个函数在文件末尾添加文字,支持格式化输出的参数:

执行以下程序代码

执行结果:打开 "D:\\Test.log" 文件,内容如下:

 

使用 CodeGuard

CodeGuard可以发现程序里面的内存泄漏和访问越界等问题。
目前 C++ Builder 10 版本,只有 Borland Win32 编译器可以使用 CodeGurad,
clang 编译器,包括 clang Win32 和 clang Win64 还都不能使用 CodeGuard。

选择菜单 Project → Options,在左面找到 C++ Compiler → Debugging,右面的 Enable CodeGuard就是这个选项,打勾选True,为启用这个功能,不打勾选False,为不启用这个功能,默认是不打勾,不启用这个功能。

如果启用了 CodeGuard,程序必须带CodeGuard调试的运行库才能运行,如果要发布程序,需要把这个去掉,重新编译。

下面的例子包含访问越界和内存泄漏:

当程序执行到光标位置就停下来,并且 CodeGuard 在 Messages 区域提示:
访问越界,在 Unit1.cpp 的 131 行,
访问4个字节在0x0267590+40,就是在偏移为0+40的位置,内存只分配了40个字节
这个数组是使用 new[] 分配的40个字节的内存。

如上图所示:程序结束的时候,CodeGurad 又在 Messages 区域增加了两行提示信息:
资源泄漏,在 Unit1.cpp 的第 129 行,
数组没有被 delete,
数组是使用 new[] 分配的 40 个字节。

程序结束的时候,在 exe 文件所在的文件夹里面,有一个和 exe 同名的 .cgl 文件,是CodeGuard创建的日志文件,可以用记事本打开查看。

例 Project1.cgl 的内容如下:

◤上一页:运行 exe 项目下一页:调试库 .dll .a .lib 或控件 .bpl 项目

C++ 爱好者 -- Victor Chen 的个人网站 www.cppfans.com 辽ICP备11016859号