必须为每个gcc -c命令添加-g,否则gdb无法加载符号表;分步编译时需对每个源文件单独加-g,一步编译则-g置于最后即可,且须清理旧.o文件确保生效。

直接加 -g 编译所有 .c 文件,再用 gdb 启动可执行文件——这是唯一可靠起点。不带 -g 的目标文件或可执行文件,gdb 无法显示源码行、变量值或设置断点。
为什么 gdb 找不到源码或显示 no symbol table
常见现象是启动 gdb ./main 后,list 显示 “No symbol table is loaded”,break main 报错 “Function main not defined”。根本原因是:编译时没加 -g,或者只给部分文件加了 -g。
-
-g必须出现在**每个gcc -c命令里**,不能只加在最后链接那步 - 如果用
gcc -o main main.c add.c max.c一步编译,-g放在最后即可:gcc -g -o main main.c add.c max.c - 如果分步编译(推荐用于调试定位),必须每步都带
-g:gcc -g -c main.c、gcc -g -c add.c、gcc -g -c max.c,再gcc -g -o main main.o add.o max.o - 检查是否生效:运行
file main,输出含 “with debug_info” 才算成功;或readelf -S main | grep debug应有若干.debug_*段
gdb 中跨文件调试的实际操作
多文件项目里,函数分布在不同 .c 中,gdb 默认只加载当前执行文件的符号。但只要所有 .o 都带 -g,它就能自动识别全部源码路径和函数。
- 启动后用
info sources查看 gdb 已知的所有源文件路径(注意路径是否真实存在,相对路径容易出错) - 用
list add可直接列出add.c全文;list add.c:5跳到第 5 行 - 设断点不依赖当前文件:
break add.c:3或break max(函数名)都有效 - 进入函数后,
frame显示当前栈帧对应哪个文件哪一行;up/down可切换调用链中的不同源文件上下文 - 若提示 “No such file or directory”,说明编译时用的是绝对路径(如
/home/user/proj/add.c),而你当前不在原路径下——此时用directory /path/to/src告诉 gdb 源码位置
Makefile 里集成调试支持容易漏掉的点
写 Makefile 时,-g 很容易只加在最终链接命令里,或者被 CFLAGS 覆盖掉。实际要确保它参与每个编译动作。
- 定义统一变量:
CFLAGS = -g -Wall -std=c99,并在所有.o规则中使用它,例如:main.o: main.c; gcc $(CFLAGS) -c main.c - 避免在链接命令里重复写
-g(虽然不报错,但冗余且易混淆) - 区分调试/发布版本时,不要用条件覆盖整个
CFLAGS,而是追加:DEBUG_FLAGS = -g -O0,然后CFLAGS += $(DEBUG_FLAGS) - 验证生成的
.o是否含调试信息:readelf -S add.o | grep debug—— 如果为空,说明该规则没用上CFLAGS
最常被忽略的是:即使你改了 Makefile 加了 -g,旧的 .o 文件不会自动重编译。务必先 make clean 或手动删掉所有 .o,再 make,否则 gdb 依然看不到源码。











