c++oding="utf-8" ?>
必须用-g编译,否则gdb无法查看变量名、行号和函数结构;需搭配-o0关闭优化,用readelf -s验证.debug_*段存在,断点应按行号或全限定名设置,崩溃后通过core文件+backtrace定位。

必须用 -g 编译,否则 GDB 看不到变量名、行号和函数结构——这不是“可能失效”,而是根本无法调试。
编译时漏掉 -g 就等于没准备调试环境
很多同学写完 C++ 代码直接 g++ main.cpp -o app,然后进 gdb ./app 发现 list 显示空、print i 报错 “No symbol 'i' in current context”。原因只有一个:编译器没生成调试信息。
-
-g是硬性前提,必须加在编译命令里,例如:g++ -g -O0 main.cpp -o app -
-O0强烈建议加上:优化(如-O2)会让变量被寄存器复用、循环被展开、代码重排,导致单步执行跳行、变量突然“消失” - 验证是否成功:运行
readelf -S app | grep debug,看到.debug_*段说明调试信息已嵌入
break 设置断点的三种常见写法及坑点
断点设不对,程序跑飞或压根不中断。C++ 场景下尤其要注意函数重载和模板实例化。
- 按行号设:
break main.cpp:15—— 最稳妥,但需确保源码路径与编译时一致(相对/绝对路径影响加载) - 按函数名设:
break std::vector<int>::push_back</int>—— 要写全名,尖括号必须转义或用单引号包裹:break 'std::vector<int>::push_back'</int> - 条件断点慎用:
break main.cpp:22 if i == 42—— 条件表达式在每次循环都求值,性能开销大;若i是寄存器变量(-O2下常见),可能报 “variable optimized out”
调试崩溃后怎么定位段错误源头
程序一跑就 Segmentation fault (core dumped),不能只靠猜。核心是让 GDB 抓住崩溃瞬间的上下文。
- 先启用 core dump:
ulimit -c unlimited(当前 shell 有效) - 运行程序触发崩溃,生成
core或core.xxx文件 - 用
gdb ./app core加载,立即执行backtrace(或bt)—— 第一行就是出错位置,比如#0 0x00005555555551a9 in main (argc=1, argv=0x7fffffffe1e8) at crash.cpp:8 - 再用
frame 0切到顶层栈帧,info registers看rip/rax是否为非法地址(如0x0),x/10i $rip查看崩溃前几条汇编指令
print 和 watch 在 C++ 中的行为差异
C++ 对象、引用、STL 容器让变量查看变得复杂。盲目 print vec 可能只看到地址,watch 也可能因内联失效。
-
print vec默认只显示std::vector对象头(size/capacity/ptr),要展开内容得:print *vec._M_impl._M_start@vec.size()(GCC libstdc++)或用pp vec(需加载 Python 自定义脚本) -
watch *ptr可以监控指针所指内存,但watch vec[0]在 vector realloc 时会失效——因为地址变了,GDB 不自动更新观察点 - 对
std::string,print str.c_str()比print str更可靠;对智能指针,print ptr.get()看原始地址,print *ptr解引用
最易被忽略的是:GDB 对 C++ 模板实例化符号的支持依赖于编译器生成的调试信息完整度。如果 g++ -g 后仍看不到某模板函数的局部变量,大概率是该函数被内联了(即使没开 -O,某些 STL 实现也会强制内联),这时得加 -fno-inline 临时编译,或者直接在调用点设断点后用 step 进入。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











