#include<stdio.h>intSum(int s, int e) {
int result = 0;
for(int i = s; i <= e; i++) {
result += i;
}
return result;
}
intmain() {
int start = 1;
int end = 100;
printf("I will begin\n");
int n = Sum(start, end);
printf("running done, result is: [%d-%d]=%d\n", start, end, n);
return0;
}
显示当前位置附近的代码(默认每次 10 行):(gdb) l 或 (gdb) list
显示指定行号附近的代码:(gdb) l 行号(示例:l 10 显示第 10 行附近代码)
显示指定函数的代码:(gdb) l 函数名(示例:l main 显示 main 函数代码)
显示指定文件的指定行代码:(gdb) l 文件名:行号(示例:l mycmd.c:1 显示 mycmd.c 第 1 行)
实战示例:
(gdb) l main # 查看 main 函数代码
14 15 int main()
16 {
17 int start = 1;
18 int end = 100;
19 printf("I will begin\n");
20 int n = Sum(start, end);
21 printf("running done, result is: [%d-%d]=%d\n", start, end, n);
22 return 0;
23 }
24
2.2 断点操作:调试的核心(break/b)
断点是调试的核心功能,用于指定程序暂停执行的位置,方便观察变量状态和程序流程。
2.2.1 设置断点
常用断点设置方式:
按行号设置断点:(gdb) b 行号(示例:b 20 在第 20 行设置断点)
按函数名设置断点:(gdb) b 函数名(示例:b Sum 在 Sum 函数开头设置断点)
按文件 + 行号设置断点(多文件项目):(gdb) b 文件名:行号(示例:b mycmd.c:10)
2.2.2 查看断点信息
使用 info break 或 info b 命令查看所有断点的详细信息:
(gdb) b 20 # 设置断点
Breakpoint 1 at 0x11c3: file mycmd.c, line 20.
(gdb) info b # 查看断点信息
Num Type Disp Enb Address What
1 breakpoint keep y 0x00005555555551c3 in main at mycmd.c:20
(gdb) r # 启动程序到断点
Breakpoint 1, main () at mycmd.c:20
20 int n = Sum(start, end);
(gdb) s # 逐语句执行,进入 Sum 函数
Sum (s=1, e=100) at mycmd.c:5
5 {
(gdb) n # 逐过程执行,执行下一行
6 int result = 0;
(gdb) n # 继续逐过程执行
7 for(int i = s; i <= e; i++)
2.3.3 继续执行(continue/c)
程序暂停在断点或单步执行后,使用 continue 或 c 命令让程序继续执行到下一个断点或程序结束:
(gdb) c
Continuing.
running done, result is: [1-100]=5050
[Inferior 1 (process 12345) exited normally]
2.3.4 执行到函数返回(finish)
在函数内部调试时,使用 finish 命令执行到当前函数返回,并显示返回值:
(gdb) s # 进入 Sum 函数
Sum (s=1, e=100) at mycmd.c:5
5 {
(gdb) finish # 执行到 Sum 函数返回
Run till exit from #0 Sum (s=1, e=100) at mycmd.c:5
0x00005555555551d2 in main () at mycmd.c:20
20 int n = Sum(start, end);
Value returned is $1 = 5050 # 显示 Sum 函数返回值
2.3.5 执行到指定行(until)
使用 until 行号 命令让程序执行到指定行,无需设置断点,适合快速跳转到目标位置:
(gdb) until 16 # 执行到第 16 行
Sum (s=1, e=100) at mycmd.c:16
16 return result;
2.4 变量操作:查看、修改与监视
调试的核心目的是观察变量取值是否符合预期,gdb 提供了丰富的变量操作命令。
2.4.1 查看变量值(print/p)
使用 print 或 p 命令查看变量、表达式的值,支持直接计算表达式。
常用用法:
查看变量值:(gdb) p 变量名(示例:p result 查看 result 变量值)
查看表达式值:(gdb) p 表达式(示例:p start+end 计算并显示 start+end 的值)
连续查看变量(自动递增序号):多次使用 p 命令,变量值会被编号($1, $2...),可通过编号快速查看历史值。
实战示例:
(gdb) s # 进入 Sum 函数
Sum (s=1, e=100) at mycmd.c:5
5 {
(gdb) n
6 int result = 0;
(gdb) p result # 查看 result 变量值
$1 = 0
(gdb) n
7 for(int i = s; i <= e; i++)
(gdb) p i # 查看 i 变量值
$2 = 1
(gdb) p s+e # 查看表达式值
$3 = 101
2.4.2 修改变量值(set var)
调试时如果发现变量取值异常,可以使用 set var 变量名=值 命令直接修改变量值,验证是否是该变量导致的问题。
实战示例:假设我们修改 Sum 函数,添加一个 flag 变量控制返回值,故意设置 flag=0 导致结果异常:
#include<stdio.h>int flag = 0; // 故意错误,导致返回值为 0intSum(int s, int e) {
int result = 0;
for(int i = s; i <= e; i++) {
result += i;
}
return result*flag; // 乘以 flag,结果为 0
}
intmain() {
int start = 1;
int end = 100;
printf("I will begin\n");
int n = Sum(start, end);
printf("running done, result is: [%d-%d]=%d\n", start, end, n);
return0;
}
调试时修改 flag 值:
(gdb) r # 启动程序
Starting program: /home/whb/test/mycmd
I will begin
Breakpoint 1, main () at mycmd.c:24
24 int n = Sum(start, end);
(gdb) s # 进入 Sum 函数
Sum (s=1, e=100) at mycmd.c:9
9 {
(gdb) n
10 int result = 0;
(gdb) n
11 for(int i = s; i <= e; i++)
(gdb) until 16 # 执行到 return 语句前
Sum (s=1, e=100) at mycmd.c:16
16 return result*flag;
(gdb) p result # 查看 result 值,正确应为 5050
$1 = 5050
(gdb) p flag # 查看 flag 值,发现为 0
$2 = 0
(gdb) set var flag=1 # 修改 flag 值为 1
(gdb) p flag # 验证修改结果
$3 = 1
(gdb) n # 执行 return 语句
17 }
(gdb) n
main () at mycmd.c:25
25 printf("running done, result is: [%d-%d]=%d\n", start, end, n);
(gdb) n
running done, result is: [1-100]=5050 # 结果正常,验证问题根源
跟踪变量:(gdb) display 变量名(示例:display i 跟踪循环变量 i)
查看跟踪列表:(gdb) info display
取消跟踪:(gdb) undisplay 跟踪编号(示例:undisplay 1 取消编号为 1 的跟踪)。
实战示例:
(gdb) s # 进入 Sum 函数
Sum (s=1, e=100) at mycmd.c:5
5 {
(gdb) n
6 int result = 0;
(gdb) n
7 for(int i = s; i <= e; i++)
(gdb) display i # 跟踪 i 变量
1: i = 1
(gdb) n
9 result += i;
1: i = 1
(gdb) n
7 for(int i = s; i <= e; i++)
1: i = 1
(gdb) n
9 result += i;
1: i = 2 # 自动显示 i 的最新值
(gdb) r # 启动程序,程序崩溃
Starting program: /home/whb/test/crash_program
Program received signal SIGSEGV, Segmentation fault.
0x0000555555555189 in func2 (p=0x0) at crash.c:8
8 *p = 10; # 空指针解引用导致崩溃
(gdb) bt # 查看函数调用栈
#0 0x0000555555555189 in func2 (p=0x0) at crash.c:8
#1 0x000055555555519e in func1 () at crash.c:13
#2 0x00005555555551b6 in main () at crash.c:19
新增断点 时直接添加条件:(gdb) b 行号/函数名 if 条件
示例:b 9 if i == 30(在第 9 行设置断点,仅当 i=30 时暂停)。
给 已有断点 添加条件:(gdb) condition 断点编号 条件
示例:condition 2 i == 30(给 2 号断点添加条件 i=30)。
3.1.2 实战示例:循环中定位特定值
假设 Sum 函数循环计算 1 到 100 的和,我们需要在 i=30 时观察 result 的值:
(gdb) r # 启动程序
Breakpoint 1, main () at mycmd.c:20
20 int n = Sum(start, end);
(gdb) s # 进入 Sum 函数
Sum (s=1, e=100) at mycmd.c:5
5 {
(gdb) n
6 int result = 0;
(gdb) n
7 for(int i = s; i <= e; i++)
(gdb) b 9 if i == 30 # 新增条件断点,i=30 时暂停
Breakpoint 2 at 0x555555555186: file mycmd.c, line 9.
(gdb) c # 继续执行
Continuing.
Breakpoint 2, Sum (s=1, e=100) at mycmd.c:9
9 result += i;
(gdb) p i # 验证 i=30
$1 = 30
(gdb) p result # 查看此时 result 的值(1+2+...+29=435)
$2 = 435
(gdb) r # 启动程序
Breakpoint 1, main () at mycmd.c:20
20 int n = Sum(start, end);
(gdb) s # 进入 Sum 函数
Sum (s=1, e=100) at mycmd.c:5
5 {
(gdb) n
6 int result = 0;
(gdb) watch result # 监视 result 变量
Hardware watchpoint 2: result
(gdb) c # 继续执行
Continuing.
Hardware watchpoint 2: result
Old value = 0
New value = 1 # 第一次变化:result=0→1
Sum (s=1, e=100) at mycmd.c:7
7 for(int i = s; i <= e; i++)
(gdb) c
Continuing.
Hardware watchpoint 2: result
Old value = 1
New value = 3 # 第二次变化:result=1→3
Sum (s=1, e=100) at mycmd.c:7
7 for(int i = s; i <= e; i++)
cgdb mycmd # 启动 cgdb
(cgdb) r # 运行程序
Starting program: /home/whb/test/mycmd
I will begin
Breakpoint 1, main () at mycmd.c:20
20 int n = Sum(start, end);
此时上半部分代码屏会高亮显示第 20 行,无需输入 list 命令即可看到当前执行位置,调试过程中代码会自动跟随执行行滚动,体验远超纯 gdb。
五、常见问题与避坑指南
5.1 无法启动 gdb 调试
问题:No debugging symbols found in 可执行程序;
原因:编译时未添加 -g 选项,程序无调试信息;
解决:重新编译,添加 -g 选项(gcc -g 源文件 -o 可执行程序)。
5.2 断点设置失败
问题:Breakpoint 1 at 0xXXXX: file 文件名.c, line 行号. (2 locations);
原因:可能是代码被优化(如使用 -O2 优化选项),导致行号对应不上;
解决:编译时关闭优化(去掉 -O 相关选项),仅保留 -g 选项。
5.3 变量无法查看
问题:No symbol "变量名" in current context.
原因:变量超出作用域,或编译优化导致变量被消除。
解决:确保在变量作用域内查看,关闭编译优化。
5.4 多文件调试路径问题
问题:多文件项目中,设置其他文件断点时提示 No such file or directory。
解决:使用 file 文件名:行号 格式设置断点,或编译时指定源文件路径。