4. 断点基础:设置/取消断点、条件断点、断点启用/禁用
调试这事儿,说白了就是让程序在关键时刻停下来,让你看看它到底在干什么。而断点,就是让程序停下来的那个「刹车」。今天咱们就聊聊断点的基本功——怎么设、怎么取消、怎么玩出花样。
4.1 设置与取消断点
设置断点最直接的方式,就是在代码行号旁边点一下。GDB 里用 break 命令,简写 b。我个人习惯在 Qt Creator 里直接点行号,但命令行下更灵活。
(gdb) break main.cpp:42 // 在 main.cpp 第 42 行设断点
(gdb) break MyClass::myMethod // 在某个成员函数入口设断点
(gdb) break *0x4005e0 // 在内存地址设断点(高级用法)
取消断点用 delete 或 clear。区别在于:delete 按断点编号删,clear 按位置删。
(gdb) info breakpoints // 查看所有断点,记住编号
(gdb) delete 2 // 删除编号为 2 的断点
(gdb) clear main.cpp:42 // 清除 main.cpp 第 42 行的断点
小技巧:用
info breakpoints 查看断点时,注意看 Num 列和 Enb 列。前者是编号,后者表示是否启用。
4.2 条件断点
条件断点是我在项目中用得最多的功能。你想想看,一个循环跑 10 万次,你只关心第 99999 次的情况,总不能一次次按 continue 吧?
(gdb) break main.cpp:42 if i == 99999
(gdb) break MyClass::update if this->m_count > 100
我曾经在调试一个 Qt 界面刷新问题时,遇到一个诡异的 bug——只有用户连续点击 5 次按钮后才出现。用条件断点 if clickCount == 5,一下子就抓住了现场。
重点:条件表达式必须是 C++ 合法的布尔表达式。GDB 会在每次命中该位置时求值,如果条件为真才停下。注意性能——条件太复杂会拖慢程序。
还有一种常见场景:调试信号槽时,你只关心某个特定 sender 发来的信号。
(gdb) break QObject::event if sender == 0x7fffffff1234
嗯,这里要注意——地址每次运行都可能变,所以更靠谱的做法是用自定义条件。
4.3 断点的启用与禁用
有时候你设了一堆断点,但暂时不想让某个断点生效。删掉吧,怕后面还要用;留着吧,每次都会停。这时候就用 enable 和 disable。
(gdb) disable 3 // 禁用编号 3 的断点
(gdb) enable 3 // 重新启用
(gdb) disable // 禁用所有断点
(gdb) enable // 启用所有断点
我个人习惯在调试初期把所有可能用到的断点都设好,然后只启用当前关心的几个。这样既不会漏掉关键位置,又不会被频繁打断。
避坑指南:我曾经在调试一个多线程程序时,禁用了某个断点后忘了重新启用,结果排查了半天找不到问题。后来发现——断点还在,只是被禁用了。所以调试完记得检查
info breakpoints,看看有没有被遗忘的禁用断点。
4.4 断点管理实战
咱们用一张图来梳理断点的核心操作:
4.5 实战经验总结
| 操作 | 命令 | 适用场景 |
|---|---|---|
| 设置断点 | break 位置 |
在函数入口、指定行号停下 |
| 条件断点 | break 位置 if 条件 |
只在满足条件时停下,如循环特定次数 |
| 禁用断点 | disable 编号 |
暂时不想用,但保留断点位置 |
| 启用断点 | enable 编号 |
恢复之前禁用的断点 |
| 取消断点 | delete 编号 或 clear 位置 |
彻底移除不需要的断点 |
我的习惯:调试 Qt 项目时,我通常先在关键信号发射处设条件断点,比如
if sender() == myButton。这样能精准定位是哪个控件触发了问题。另外,info breakpoints 是我调试时敲得最多的命令之一——随时掌握断点状态,心里才有底。
断点这东西,看似简单,但用好了能省下大把时间。别小看这些基础操作——我见过不少开发者只会点行号设断点,条件断点和启用/禁用压根没用过。说白了,调试效率的差距,往往就体现在这些细节上。