GDB
1.什么是GDB
GDB 是由 GNU 软件系统社区提供的调试工具,同 GCC 配套组成了一套完整的开发环境,GDB 是 Linux 和许多 类Unix系统的标准开发环境。
一般来说,GDB 主要能够提供以下四个方面的帮助:
- 启动程序,可以按照自定义的要求随心所欲的运行程序;
- 可以让被调试的程序在所指定的设置的断点处停住(断点也可以是条件表达式);
- 当程序被停住时,可以检查当前程序的中的变量的状态;
- 可以修改程序,将一个 BUG 产生的影响修正从而测试其他BUG;
2.准备工作
通常,在为调试而编译时,我们需要关掉优化选项 -O
,并且打开调试选项 -g
。
另外,-Wall
会在尽量不影响程序行为的情况下选择打开所有的 warning
,也可以发现许多问题,可以避免一些不必要的 BUG。
gcc -g -Wall program.c -o program
-g
选项的作用是在可执行文件中加入源代码的信息,比如可执行文件中第几条机器指令对应源代码的第几行,但是并不是把整个源文件嵌入到可执行文件中,所以在调试的时候必须保证 GDB 能找到源文件。
3.GDB命令——启动、退出、查看代码
使用如下的几个文件来测试:
main.c
#include <stdio.h>
#include <stdlib.h>
#include "head.h"
int main(int argc,char* argv[]){
int a , b;
if(argc < 3){
a = 10 , b = 20;
}
else{
a = atoi(argv[1]);
b = atoi(argv[2]);
}
printf("a = %d , b = %d\n",a,b);
printf("a + b = %d\n",add(a,b));
printf("a - b = %d\n",sub(a,b));
printf("a * b = %d\n",mul(a,b));
printf("a / b = %.2lf\n",divide(a,b));
printf("xixixiixixixi\n");
printf("hello makefile\n");
for(int i = 0;i < 20;i++){
printf("%d ",i + 1);
}
printf("\n");
return 0;
}
head.h
#include <stdio.h>
int add(int a,int b);
int sub(int a,int b);
int mul(int a,int b);
double divide(int a,int b);
add.c
#include "head.h"
int add(int a,int b){
return a + b;
}
sub.c
#include "head.h"
int sub(int a,int b){
return a - b;
}
mul.c
#include "head.h"
int mul(int a,int b){
return a * b;
}
div.c
#include "head.h"
double divide(int a,int b){
return a * 1.0 / b;
}
Makefile
src=$(wildcard *.c)
objs=$(patsubst %.c,%.o,$(src))
target=app
$(target):$(src)
$(CC) $(src) -o $(target) -g
.PHONY:clean
clean:
rm $(objs) -f
1.启动和退出
gdb
可执行文件;quit / q
;
首先使用 make
生成带有调试信息的可执行程序 app
,接着再使用 gdb
启动和退出。
2.给程序设置参数 / 获取参数
set args 10 20 ...
;show args
;
3.GDB 使用帮助
help
;
4.查看当前文件代码
list / l
(从默认位置开始显示);list / l
行号 (从指定行开始显示,指定的行号在中间);list/l
函数名 (从指定函数显示);
默认是从起始位置开始显示的。
显示第 20 行。
显示 main
函数。
5.设置显示的行数
show list / listsize
;set list / listsize 行数
;
默认只显示 10 行。
将其修改为 20 行,再查看代码。
6.查看非当前文件的代码
list / l 文件名:行号
;list / l 文件名:函数名
;
查看 add.c
文件的第 5 行。
查看 sub.c
文件的 sub()
函数。
4.GDB命令——断点操作
1.设置断点
break / b 行号
;break / b 函数名
;break / b 文件名:行号
;break / b 文件名:函数
;
默认文件第 10 行设置断点。
main
函数设置断点。
在 add,c
文件中,第 3 行设置断点。
在 sub.c
文件中,sub()
函数设置断点。
2.查看断点
info / i break / b
;
查看第一步设置的断点信息。
3.删除断点
delete / del / d 断点编号
;
删除编号为 3 的断点,也就是 add.c
第 3 行的断点。
4.设置断点无效
disable / dis 断点编号
;
将 1号断点设置为无效。
5.设置断点生效
enable / ena 断点编号
;
设置 1号断点 生效。
6.设置条件断点(一般用在循环体中)
break / b 行号 if i==5
;
main.c
的 28 行是一个循环,当 i ==10
时,给 28行 设置一个断点。
需要注意的是,当退出 gdb
之后,你之前设置的断点就都没有了。
5.GDB命令——调试命令
1.运行 GDB 程序
start
(程序停在第一行);run
(遇到断点才停);
给 main.c
的 20行 设置一个断点。
start
run
2.继续运行,遇到下一个断点才停
continue / c
;
在 main.c
24行 再设置一个断点。
run
启动程序来到 20行。
接着再执行 continue / c
命令,就会来到下一个断点处,也就是 24行。
如果后面没有断点了,再执行 continue / c
命令,程序就会执行到最后,执行完毕。
3.向下执行一行代码(不会进入函数体)
next / n
;
4.变量操作
print 变量名
(打印变量的值);ptype 变量名
(打印变量数据类型);
5.向下单步调试
step / s
(会进入函数体);finish
(调出函数体);
6.自动变量操作
display num
(自动打印指定变量num
的值);info / i display
(显示有哪些自动变量);undisplay 编号
(取消指定的自动变量);
7.其他操作
set var 变量名=变量值
(定义变量);until
(跳出循环);