必须为所有源文件加 -g 编译,否则 GDB 无法调试;list 可加载其他文件源码后设断点;step 进入函数、next 不进;info sources/functions 确认符号是否加载成功。

必须先用 -g 编译所有源文件
不加 -g 就根本没法单步——GDB 会直接提示 No debugging symbols found,list、step、next 全部失效。多文件项目里,哪怕只漏一个 .c 没加 -g,它对应的函数内部就看不到源码,step 进去也会变成汇编指令。
正确做法是:所有参与链接的源文件,编译时都带 -g。比如:
gcc -g -c main.c -o main.o gcc -g -c add.c -o add.o gcc main.o add.o -o program
或者更稳妥地用 Makefile 统一控制:CFLAGS = -g -Wall,避免个别文件遗漏。
用 list 查看其他文件的代码再设断点
GDB 默认只显示当前停靠位置的源文件(通常是 main.c),想在 add.c 里设断点,得先让它“看见”那个文件。
-
list add.c:1—— 显示add.c开头几行 -
list add.c:func_name—— 显示add.c中func_name函数的源码 - 显示完后,直接输
break 5就是在当前文件(即add.c)第 5 行设断点 - 或者跳过显示步骤,直接
break add.c:5或break add(函数名)
注意:break add 是按函数名设断点,GDB 会自动定位到 add.c 里的定义处,前提是符号没被优化掉(所以别用 -O2 以上)。
step 和 next 的行为差异直接影响是否进入其他文件
这是最容易混淆的点:单步命令不是“走一行代码”,而是“走一条可执行语句”,而是否跨文件取决于你选哪个命令。
-
next(简写n):不进函数体。调用add()时,它会直接执行完并停在下一行(仍在main.c),无论add.c有没有断点 -
step(简写s):强制进入被调函数。只要add.c有调试信息,step就会跳进add.c的第一行,哪怕那里没设断点 -
finish(简写fin):从当前函数返回,回到调用它的那一行(比如从add.c回到main.c)
如果误用 next 跳过了关键逻辑,别重启——用 step 进入、finish 退出,比重跑快得多。
info sources 和 info functions 帮你确认文件和符号是否加载成功
调试卡住、找不到函数、list 报错时,别猜。先运行这两个命令:
-
info sources—— 列出所有被 GDB 成功读取的源文件路径。如果add.c不在里面,说明编译漏了-g或路径不对 -
info functions—— 列出所有已知函数名。如果add不在列表里,大概率是函数被内联(-O2导致)或声明/定义不匹配
这两个命令输出干净、无歧义,比反复试 list 更省时间。尤其当项目有几十个源文件时,一眼就能定位缺失环节。











