必须加-g且搭配-O0,因-g仅嵌入调试符号,而-O2/O3等优化会重排代码、删除变量,导致next跳行、print失败、断点失效;-ggdb比-g多GNU扩展信息但兼容性差;调试信息不可事后添加。

-g 是必须加的编译参数,没有它,GDB 几乎无法做源码级调试。
为什么只加 -g 不够?
加了 -g 只是让编译器把行号、变量名、函数名等调试信息写进可执行文件,但实际调试时还可能卡在几个地方:
- 如果用了
-O2或-O3这类优化选项,编译器会重排、内联、删减代码,导致next跳行、print看不到变量、断点设不上 —— 建议搭配-O0使用 - 某些 C++ 模板或内联函数在低版本标准下调试信息不全,可追加
-std=c++17(或项目对应的标准) - 用
file命令检查是否真含调试段:file ./a.out输出里应有 “with debug_info”;更准一点用readelf -S ./a.out | grep debug,看到.debug_*段才靠谱
-g 和 -ggdb 有什么区别?
两者都生成调试信息,但细节不同:
-
-g:通用格式(DWARF),兼容性最好,所有支持 DWARF 的调试器都能读 -
-ggdb:GNU 扩展版,额外包含 GDB 特有的符号(比如宏定义、更细粒度的行号映射),但其他调试器可能忽略或报错 - 日常开发用
-g就够;如果发现 GDB 显示变量值异常、跳转不准,再试-ggdb
调试信息能后期补上吗?
不能。调试信息必须在编译链接阶段嵌入,运行时或事后无法“注入”。常见误区:
-
strip ./a.out会直接删掉所有.debug_*段,之后再用gdb ./a.out就只能看汇编,list报 “No symbol table is loaded” - 有人想用
objcopy --add-gnu-debuglink=xxx.debug ./a.out分离调试信息,但这要求你**事先保留了带-g编译出的原始文件**,不是补救手段 - 如果只有 release 版二进制且没留 debug 版,基本只能反汇编硬啃,别指望还原出变量名或源码行
最稳妥的做法:每次改完代码,用 gcc -g -O0 或 g++ -g -O0 重新编译,哪怕多花两秒——省下的调试时间远不止这点。


















