Skip to main content

Debug

📅 2026-04-09 ✏️ 2026-04-09 CS
No related notes

1 · Debug#

  • S:程序出了 bug——行为不符合预期、崩溃、输出错误。
  • C:程序运行太快、状态太多,靠肉眼读代码和加 print 效率低下,尤其面对多线程、内存错误、复杂调用链时几乎无能为力。
  • Q:如何系统性地定位 bug 的根因,而不是靠猜?
  • A:确认原则——调试是科学方法:提出假设 → 用工具冻结现场 → 看证据 → 缩小范围 → 确认根因。调试器就是加速这个循环的核心工具。

1.1 · 调试器的核心能力

调试器做的事情就四件:

  1. 停下来(断点)—— 在指定位置暂停程序
    • 普通断点:按行号/函数名设置
    • 条件断点:满足条件才停(如 break if x > 100
    • 监视点(watchpoint):变量值变化时停
    • 断点可以附加命令列表,停下时自动执行
  2. 看状态(检查变量)—— 冻结现场后观察
    • 检查普通变量、动态数组、C++ 对象
    • 监视局部变量
    • 直接检查内存地址
    • print 一次性查看,display 每步自动显示
  3. 走一步(单步执行)—— 控制执行粒度
    • step:进入函数内部
    • next:跳过函数调用
    • continue:继续运行到下一个断点
    • finish:运行完当前函数再停
  4. 看来路(调用栈)—— 追溯”谁调用了谁”
    • 上下移动调用栈,查看每层的变量状态

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 · 一句话总结

调试 = 断点停住 → 检查状态 → 单步推进 → 回溯调用栈 → 缩小范围 → 确认根因。工具只是加速这个循环。