-g生成的调试信息直接嵌入目标文件(.o)或可执行文件,以DWARF格式存储,不产生独立文件;-g等价于-g2,包含行号、变量名、函数名等基本信息,-g1仅含基础符号,-g3额外包含宏定义。

g++ 加 -g 后生成的调试信息存哪儿了
加 -g 不会额外生成独立文件,调试信息直接嵌入到目标文件(.o)或可执行文件里,以 DWARF 格式存储。这意味着你用 file ./a.out 能看到 “with debug_info”,但用 ls -l 看不到新文件。
常见误区是以为要配 -g3 才有完整信息——其实 -g(等价于 -g2)已包含行号、变量名、函数名、基本类型定义;-g3 只多加宏定义,多数场景没必要。
-
-g:默认级别,够用 -
-g1:仅基础符号(如函数入口),GDB 无法单步或看变量 -
-g3:含宏,编译慢、体积大,仅调试宏逻辑时考虑
调试信息在什么阶段生效
调试信息必须贯穿整个构建链:源码 → 目标文件 → 最终可执行文件。只要中间任一环节没带 -g,最终程序就丢调试能力。
比如分步编译时漏了 -g:
立即学习“C++免费学习笔记(深入)”;
g++ -c main.cpp -o main.o # ❌ 没 -g,main.o 无调试信息 g++ main.o util.o -o app # ❌ 即使这步加 -g 也补不回
正确写法是每一步都加:
g++ -g -c main.cpp -o main.o g++ -g -c util.cpp -o util.o g++ -g main.o util.o -o app
- 链接时不加
-g通常不影响(因为目标文件已有) - 但建议统一加,避免混淆;且某些优化(如
-flto)可能依赖链接期调试信息
和 -O 优化共存时的坑
-g 和 -O 可以一起用,但 GDB 行为会变:变量可能被优化掉、代码重排导致单步“跳行”、内联函数看不到栈帧。
开发调试阶段推荐:
- 先用
-g -O0确保行为可预测 - 确认逻辑正确后,再试
-g -O2查性能问题 - 别用
-g -O3调逻辑——优化太激进,GDB 很难对齐源码
一个典型现象:print my_var 在 GDB 里显示 <optimized out></optimized>,就是变量被 -O2 以上干掉了,不是 -g 没起作用。
怎么验证 -g 是否真生效了
别只信编译命令里写了 -g,得实测。最直接的方法:
readelf -S ./app | grep debug
看到类似 .debug_info、.debug_line 的段就说明成功。或者更简单:
gdb ./app -ex "list main" -ex quit 2>/dev/null | head -n 5
如果输出了源码行,说明调试信息可用;如果报 main not defined 或空输出,大概率没生效。
容易忽略的一点:CMake 或 Makefile 里,CXXFLAGS 被覆盖(比如后面又赋值一次)会导致 -g 丢失,建议用 make VERBOSE=1 看实际调用的 g++ 命令。


















