GDB tutorial
撸码10分钟,DEBUG2小时。
有IDE的时候可以用IDE提供的Debugger,没有IDE的时候不能总靠printf, cout来debug,效率太低,所以好好学习一下GDB的用法。
使用GDB一定要记得在compile的时候加上-g,-g会告诉compiler不要优化代码,保留它原本的样子,只有这样,才可以一行一行去debug,知道代码问题出在哪里。
GDB overview
假如我们有一个test.cpp长这样:
#include <iostream>
#include <string>
int main(int argc, char** argv){
int j = atoi(argv[1]);
int k = atoi(argv[2]);
j = k+3;
k = j*k;
std::cout << "the result is " << k << std::endl;
return 0;
}
我们用g++ -g来编译,生成一个名为test的可执行文件:
g++ -g test.cpp -o test
load executable file into GDB
要用GDB来debug,只需要运行:
gdb ./test
这条指令会让我们可以在GDB里面运行我们的程序test
因为./test 需要两个参数,我们可以在这一步使用–args传入,比如传入参数1,2:
gdb --args ./test 1 2
也可以就像前面那样,直接载入,然后在GDB里面传入。
run program in GDB
如果前面没有使用–args传入参数的话,那么在gdb里面运行的时候,我们需要传入两个参数,然后使用指令run来执行:
(gdb) run 1 2
如果已经使用了–args传入了参数,直接使用指令run,然后开始运行载入gdb的可执行文件test:
(gdb) run // 也可以使用简写r
这样的运行结果和不使用GDB的运行结果是一样的,我们可以得到:
(gdb) run 1 2
Starting program: /localdisk/home/test 1 2 // 程序所在位置
the result is 10 // 程序输出
[Inferior 1 (process 78344) exited normally] //程序运行状态
quit GDB
要退出GDB,只需要使用quit或者q
(gdb) quit
(gdb) q
上面几个指令只是介绍了最基本的GDB的使用方法。要真正发挥GDB的作用,我们需要学习如下指令:
GDB commands
break
break指令用于设置断点,可以给break传入你想要停止的line number,也可以给break传入你想要停止的function name, 比如:
(gdb) break main
Breakpoint 1 at 0x4011a5: file test.cpp, line 5.
会在执行到main()的时候停下来,等待进一步地指令。
(gdb) break 7
Breakpoint 2 at 0x4011d1: file test.cpp, line 7.
会在第七行停下来,等待进一步地指令。
next
当设置好断点之后,使用run开始运行程序,程序会在断点的地方停下来。如果我们想要执行下一步,就可以使用next (也可以使用简写n):
(gdb) run 1 2
Starting program: /localdisk/mdu5/test 1 2
Breakpoint 1, main (argc=3, argv=0x7fffffffd768) at test.cpp:5
5 int j = atoi(argv[1]);
(gdb) next
6 int k = atoi(argv[2]);
note: 当使用next的时候,打印出来的是即将执行,但是还没有被执行的code。比如上面next显示第6行,其实这一行目前还没有开始执行。
list
如果程序很长,每次使用next只会print正在执行的单行代码,让人搞不清整个程序在做些什么。这个时候就可以使用list来看看当前代码上下文:
(gdb) list
1 #include <iostream>
2 #include <string>
3
4 int main(int argc, char** argv){
5 int j = atoi(argv[1]);
6 int k = atoi(argv[2]);
7 j = k+3;
8 k = j*k;
9 std::cout << "the result is " << k << std::endl;
10 return 0;
这样,我们就可以清楚看到,我们执行到第6行,第6行的前后代码长这样(只打印部分前后代码)。
如果我们想要检查程序运行过程中,某个变量的具体值,可以使用print:
(gdb) print j
$1 = 1
(gdb) print k // 我们前面提到,line 6即将执行,但是还没有执行
$2 = 0 // 所以k的值是0,而不是2
GDB非常强大的一点在于,它不止可以print某个变量的值,甚至可以print一些表达式的值:
(gdb) n // next 的缩写
Breakpoint 2, main (argc=3, argv=