Debug
No related notes
Outlinks (0)
No outlinks found
Backlinks (0)
No backlinks found
1 · Debug#
- S:程序出了 bug——行为不符合预期、崩溃、输出错误。
- C:程序运行太快、状态太多,靠肉眼读代码和加 print 效率低下,尤其面对多线程、内存错误、复杂调用链时几乎无能为力。
- Q:如何系统性地定位 bug 的根因,而不是靠猜?
- A:确认原则——调试是科学方法:提出假设 → 用工具冻结现场 → 看证据 → 缩小范围 → 确认根因。调试器就是加速这个循环的核心工具。
1.1 · 调试器的核心能力
调试器做的事情就四件:
- 停下来(断点)—— 在指定位置暂停程序
- 普通断点:按行号/函数名设置
- 条件断点:满足条件才停(如
break if x > 100) - 监视点(watchpoint):变量值变化时停
- 断点可以附加命令列表,停下时自动执行
- 看状态(检查变量)—— 冻结现场后观察
- 检查普通变量、动态数组、C++ 对象
- 监视局部变量
- 直接检查内存地址
- print 一次性查看,display 每步自动显示
- 走一步(单步执行)—— 控制执行粒度
- step:进入函数内部
- next:跳过函数调用
- continue:继续运行到下一个断点
- finish:运行完当前函数再停
- 看来路(调用栈)—— 追溯”谁调用了谁”
- 上下移动调用栈,查看每层的变量状态
1.2 · 程序崩溃处理
崩溃的本质是非法内存访问:
- 程序内存布局:代码段、数据段、堆、栈
- 操作系统用页管理内存,访问未映射的页 → 段错误(SIGSEGV)
- 轻微越界可能不崩溃(恰好落在合法页内),这更危险
- 核心文件(core dump)= 崩溃现场快照,用调试器加载即可还原
1.3 · 多活动上下文调试
复杂度升级:不止一个执行流
- 客户端/服务器:同时 attach 两个进程
- 多线程:切换线程上下文,查看各线程状态
- 并行程序(OpenMP / MPI):消息传递 vs 共享内存,各有调试策略
1.4 · 调试器之外的武器
| 工具 | 用途 |
|---|---|
编译器警告(-Wall) | 编译期就抓住一批问题 |
| strace / ltrace | 跟踪系统调用/库调用,看程序和OS的交互 |
| lint / splint | 静态分析,不运行就能找潜在错误 |
| Electric Fence / glibc 工具 | 检测堆内存越界、double free 等动态分配问题 |
| 文本编辑器 | 语法高亮 + 括号匹配 = 肉眼排错第一道防线 |
1.5 · 一句话总结
调试 = 断点停住 → 检查状态 → 单步推进 → 回溯调用栈 → 缩小范围 → 确认根因。工具只是加速这个循环。