C++怎么调试程序_C++调试技巧教程【高效】

1次阅读

gdb断点未触发需检查是否编译带-g;core dump缺失通常因ulimit -c 0或core_pattern配置异常;调试vector时避免直接print v[100],应先确认size再用迭代器访问。

C++怎么调试程序_C++调试技巧教程【高效】

gdb 断点没触发?检查编译时是否带 -g

不加 -g,gdb 就看不到变量名、行号、函数名,断点只能打在地址上,实际等于“盲调”。哪怕只用 g++ main.cpp -o app 编译,gdb 里 break main 都可能失败或跳转错行。

实操建议:

立即学习C++免费学习笔记(深入)”;

  • 编译命令必须包含 -g,推荐加 -O0 关闭优化(尤其涉及内联、循环展开时,-O2 下变量可能被优化掉)
  • 确认符号存在:file app 输出应含 “with debug_info”,readelf -S app | grep debug 应列出多个 .debug_*
  • 如果用 CMake,确保 set(CMAKE_BUILD_TYPE Debug) 或手动传 -DCMAKE_BUILD_TYPE=Debug

core dump 找不到?先看 ulimit -c/proc/sys/kernel/core_pattern

程序段错误后没生成 core 文件,大概率不是代码问题,而是系统限制。linux 默认可能设 ulimit -c 0,直接禁掉 core dump;或者 core_pattern 被重定向到 /dev/NULL 或某个不可写路径。

实操建议:

立即学习C++免费学习笔记(深入)”;

  • 临时放开:运行前执行 ulimit -c unlimited(注意是当前 shell 有效)
  • 查当前 pattern:cat /proc/sys/kernel/core_pattern,常见值如 core(当前目录)、core.%e.%p(带进程名和 pid)
  • 若 pattern 是管道(如 |/usr/share/apport/apport %p %s %c %d %P),core 不会落地为文件,需改回普通路径或关掉 apport

std::vector 迭代器失效?别在 gdb 里用 print v[100] 直接访问

gdb 的表达式求值器(特别是老版本)对 STL 容器支持有限。print v[100] 看似方便,但可能触发越界访问、引发二次 crash,或返回完全错误的值——因为 gdb 并不真正走 operator[] 的边界检查逻辑,而是按内存布局硬读。

实操建议:

立即学习C++免费学习笔记(深入)”;

  • 优先用 print v.size()print v.capacity() 确认范围,再用 print *(v.begin() + 100)(前提是 100
  • 启用 pretty printer:确认 ~/.gdbinit 加载了 Python 自带的 libstdc++ printers(GDB 7.7+ 默认启用,但某些嵌入式工具链可能缺失)
  • 对复杂结构体成员,避免 print obj.member.submember 连写,分步 print &obj.member 查地址更稳

线程卡死?info Threadsthread apply all bt 必须一起用

单看主线程往往看不出问题。一个线程在 pthread_mutex_lock 卡住,另一个在 malloc 里等锁,第三个刚触发 SIGSEGV——不全量看,容易误判为“主线程崩溃”。

实操建议:

立即学习C++免费学习笔记(深入)”;

  • 停住后第一件事:info threads 看所有线程状态(R 运行中、S 睡眠、T 已暂停),标出 ID
  • 挨个查堆栈:thread apply all bt(简写 taa bt),重点找 futex_wait__lll_lock_waitsem_wait 这类阻塞点
  • 若某线程停在 nanosleepepoll_wait,未必是问题,但若多个线程都卡在锁相关函数,基本就是死锁或资源争用

线程调度和信号处理的细节藏得很深,比如 sigwaitsignal 混用、pthread_cancel 配置不当,都可能导致 gdb 看到的线程状态和实际行为错位——这时候得结合 /proc/PID/status 里的 Statevoluntary_ctxt_switches 辅助判断。

text=ZqhQzanResources