【C++】使用gdb在命令行下调试C++程序(二)
如果你没看过上篇文章,建议你看看上篇【C++】使用gdb在命令行下调试C++程序(一)
这篇文章补充上次没写完的gdb调试。
我就是要在Linux上安装gdb
好的,我将WSL搭载的Linux发行版从24.04
降级到22.04
,结果gcc
gdb
全部安装成功了。
sudo apt install gcc
sudo apt install gdb
这说明真的就是24.04
的问题,但是为什么我也不太清楚,可能因为22.04默认安装gcc11
,而24.04默认安装gcc14。所以如果你也有类似的问题,可以尝试降级。
打印/追踪变量
我们在函数的21行打一个断点:
Thread 1 hit Breakpoint 1, main () at testOP.cpp:21
21 S s2{1};
此时运行,使用p 变量名
来打印变量的名字
(gdb) p s2
$1 = {num = 8}
由于s2
还没被赋值,此时打印的是内存的残留数据,再运行一行,s2
的值就有了:
(gdb) n
22 cout << (s1 == s2) << endl;
(gdb) p s2
$7 = {num = 1}
使用display 变量名
可以追踪变量,每次执行操作时都会打出变量的值:
(gdb) b 21
Breakpoint 3 at 0x7ff619ac146e: file testOP.cpp, line 21.
(gdb) r
Starting program: D:\Codes\leetcode\3133\test.exe
[New Thread 4288.0x2c34]
[New Thread 4288.0x67ec]
[New Thread 4288.0x3718]
Thread 1 hit Breakpoint 3, main () at testOP.cpp:21
21 S s2{1};
(gdb) display s1
1: s1 = {num = 1}
(gdb) n
22 cout << (s1 == s2) << endl;
1: s1 = {num = 1}
需要注意的是display
操作需要在程序运行时执行,否则会找不到符号:No symbol "s1" in current context.
undisplay 变量编号
,可以取消跟踪,比如上面的s1编号就是1(前面那个数字)
(gdb) n
22 cout << (s1 == s2) << endl;
1: s1 = {num = 1}
(gdb) undisplay 1
(gdb) n
1
23 }
打印函数堆栈
bt
可以打印函数的堆栈
(gdb) bt
#0 main () at testOP.cpp:21
(gdb) r
The program being debugged has been started already.
Start it from the beginning? (y or n) n
Program not restarted.
(gdb) s
S::S (this=0x5ffec8, num=1) at testOP.cpp:8
8 S(int num) : num(num) {};
(gdb) bt
#0 S::S (this=0x5ffec8, num=1) at testOP.cpp:8
#1 0x00007ff619ac147f in main () at testOP.cpp:21
比如我在进入S的构造函数以后,此函数就取代了main函数成为新的栈顶。
赋值
可以使用set var 变量名=值
对变量进行赋值
(gdb) display s1
2: s1 = {num = 1}
(gdb) set var s1=2
(gdb) n
22 cout << (s1 == s2) << endl;
2: s1 = {num = 2}
大体上来说这种赋值需要遵循C++的语法,比如
- 需要保证变量是可以赋值的,不能为const,不能在当前作用域不可见——比如gdb还没运行到函数内部,就对函数内的局部变量赋值,等等。
- 不能对有多个成员的结构体赋总值,但是可以按C++语法用大括号。
总之,代码里不能进行的赋值操作,set var
也不行。
开启 / 禁用断点
disable b
使所有断点无效
(gdb) info b
Num Type Disp Enb Address What
3 breakpoint keep y 0x00007ff619ac146e in main() at testOP.cpp:21
breakpoint already hit 1 time
4 breakpoint keep y 0x00007ff619ac145d in main() at testOP.cpp:20
(gdb) disable b
(gdb) info b
Num Type Disp Enb Address What
3 breakpoint keep n 0x00007ff619ac146e in main() at testOP.cpp:21
breakpoint already hit 1 time
4 breakpoint keep n 0x00007ff619ac145d in main() at testOP.cpp:20
enable b
使所有断点有效
(gdb) enable b
(gdb) info b
Num Type Disp Enb Address What
3 breakpoint keep y 0x00007ff619ac146e in main() at testOP.cpp:21
breakpoint already hit 1 time
4 breakpoint keep y 0x00007ff619ac145d in main() at testOP.cpp:20
disable b 编号
使一个断点无效
enable b 编号
使一个断点有效
指定行号跳转
until 行号
进行指定位置跳转,执行完区间代码
(gdb) b 20
Breakpoint 5 at 0x7ff619ac145d: file testOP.cpp, line 20.
(gdb) r
Starting program: D:\Codes\leetcode\3133\test.exe
[New Thread 25504.0x5ab0]
[New Thread 25504.0x559c]
[New Thread 25504.0x550c]
Thread 1 hit Breakpoint 5, main () at testOP.cpp:20
20 S s1{1};
2: s1 = {num = 0}
(gdb) until 22
main () at testOP.cpp:22
22 cout << (s1 == s2) << endl;
2: s1 = {num = 1}
这里直接一路执行到代码的22行
结束函数
finish
在一个函数内部,执行到当前函数返回
(gdb) r
Starting program: D:\Codes\leetcode\3133\test.exe
[New Thread 17196.0x1850]
[New Thread 17196.0x2fbc]
[New Thread 17196.0x3ab0]
Thread 1 hit Breakpoint 5, main () at testOP.cpp:20
20 S s1{1};
2: s1 = {num = 0}
(gdb) s
S::S (this=0x5ffecc, num=1) at testOP.cpp:8
8 S(int num) : num(num) {};
(gdb) finish
Run till exit from #0 S::S (this=0x5ffecc, num=1) at testOP.cpp:8
main () at testOP.cpp:21
21 S s2{1};
2: s1 = {num = 1}
使用step
步进到构造函数中,finish
直接跳出函数。
跳转到下一个断点
c
从一个断点处,直接运行至下一个断点处
(gdb) r
Starting program: D:\Codes\leetcode\3133\test.exe
[New Thread 2180.0x227c]
[New Thread 2180.0x55c4]
[New Thread 2180.0x6080]
Thread 1 hit Breakpoint 5, main () at testOP.cpp:20
20 S s1{1};
2: s1 = {num = 0}
(gdb) c
Continuing.
Thread 1 hit Breakpoint 6, main () at testOP.cpp:21
21 S s2{1};
2: s1 = {num = 1}
gdb在20行命中第一个断点,然后我们直接跳到21行下一个断点。