断点设置:让程序在你想停的地方停下来

调试C/C++程序,说白了就是回答三个问题:程序现在在哪?它怎么到这的?它接下来要去哪?而断点,就是我们回答这些问题的起点。

我个人习惯把断点比作「路障」。你在代码的某个位置放一个路障,程序跑到那就得停下来,把现场交给你检查。今天我们就来聊聊GDB里各种断点的玩法。

1. break命令:最基础的断点

break(简写b)是最常用的命令。用法很简单:

(gdb) break main          # 在main函数入口停
(gdb) break 42             # 在第42行停
(gdb) break file.c:100     # 在file.c的第100行停
(gdb) break func_name      # 在某个函数入口停

我在项目中遇到过一种情况:一个函数被调用了上千次,我只想在某次特定调用时停下来。这时候就需要条件断点了。

2. 条件断点:精准打击

条件断点就是带条件的break。格式是:

(gdb) break 42 if i == 5
(gdb) break func if ptr != NULL
(gdb) break file.c:100 if count > 100 && flag == 1

嗯,这里要注意:条件表达式里不能有宏定义,因为GDB不认识宏。我曾经在这个坑里摔过一次——调试一个内核模块,条件里用了#define MAX_SIZE 1024,结果GDB直接报错。后来我改成直接写数字才搞定。

小技巧:条件断点每次命中都会重新计算条件。如果条件计算很慢(比如遍历链表),程序会变得非常卡。我建议先用普通断点确认位置,再改成条件断点。

3. 临时断点:用完即走

有时候你只想停一次,比如确认某个路径是否被执行到。这时候用tbreak(temporary break):

(gdb) tbreak 42
(gdb) tbreak func
(gdb) tbreak file.c:100 if x == 0

临时断点命中一次后自动删除。我个人习惯在「我就看一眼这里会不会走到」的场景下用,省得后面还要手动清理。

4. 硬件断点:调试只读内存

硬件断点(也叫数据断点、观察点)用来监控内存变化。用watch命令:

(gdb) watch var          # 变量被写入时停
(gdb) watch *(int*)0x7fff1234  # 监控某个地址
(gdb) rwatch var         # 变量被读取时停
(gdb) awatch var         # 变量被读写时都停

硬件断点依赖CPU的调试寄存器,数量有限(通常是4个)。我记得有一次调试一个内存越界问题,变量被莫名其妙改写了。用watch监控那个变量,程序一跑就停——原来是另一个线程通过野指针写到了这里。

注意:硬件断点对局部变量要小心。变量离开作用域后,GDB会自动删除对应的watch。如果你在函数里watch了一个局部变量,函数返回后watch就失效了。

5. 断点管理:info、disable、enable、delete

断点多了以后,管理就变得重要。GDB给每个断点分配一个编号,从1开始递增。

命令 作用 示例
info breakpoints 列出所有断点 info b
disable N 禁用某个断点 disable 2
enable N 启用某个断点 enable 2
delete N 删除某个断点 delete 2
clear 删除当前行的断点 clear 42

info breakpoints的输出里,每个断点会显示:编号、类型(break/watch/catch)、是否启用(y/n)、位置、条件(如果有)。

我常用的一个技巧:调试循环时,先disable掉循环体内的断点,等程序跑到循环外再enable回来。这样不用反复设置删除。

知识体系总览

下面这张图帮你理清断点的分类和关系:

GDB断点体系 断点 (Breakpoints) 普通断点 (break) 按行号/函数/文件设置 条件断点 (break if) 满足条件才触发 临时断点 (tbreak) 命中一次自动删除 硬件断点 (watch) 监控内存读写 断点管理 info / disable / enable / delete / clear

核心要点:

  • 普通断点按位置停,条件断点按条件停,临时断点停一次就消失
  • 硬件断点监控内存,适合追踪变量被谁改了
  • 断点管理命令要熟记:info查看、disable/enable开关、delete删除
  • 条件断点表达式里不要用宏,GDB不认识

说实话,断点这东西看着简单,但用好了能省大量时间。我见过不少同事调试时满屏幕设断点,跑起来到处停,反而把自己搞晕了。我的建议是:少而精。先想清楚你要查什么问题,再决定在哪个位置设断点。条件断点能帮你过滤掉99%的不相关命中,值得花时间写好条件。

好了,断点就聊到这。下一节我们聊聊怎么在断点停住后查看程序状态——那才是真正开始「调试」的时候。

可可精品资料库