20分钟学会GDB调试技巧

在linux下的C/C++编程中,调试是经常会用到的手段,在没有可视化调试的情况下,往往就需要用到最原始高效的工具——GDB。如果需要对可执行程序作调试,那么在编译程序时就需要加上部分编译选项(-g)才能使生成的可执行程序具备调试信息。

# 编译可执行文件,最简单例子
g++ test.cc # 没有调试信息
g++ -g test.cc #有调试信息

如果没有-g,当你想使用gdb命令调试程序时,会提示“(No debugging symbols found in a.out)”,你也就无法正常地使用接下来的gdb相关命令操作了。

同样地,如果对于已编译完的可执行程序,可以通过strip命令移除调试信息,移除后的可执行文件可以明显看出来占用空间变少。

strip a.out

下面进入正文。

1.启动gdb

# 第一种直接+可执行文件启动
gdb    ... # file_name为可执行文件,param表示命令行参数(如果有)
# 第二种,可以先启动gdb再跟可执行文件
gdb
file  #指定可执行文件
set args   ...  #指定命令行参数(如果有)

2.常用命令

命令 缩写 说明
run r 启动程序
break b

添加断点,有两种写法:

1)break file.cpp:30,表示在file.cpp的第30行打断点。

2)break xxclass::xxfunc(),表示在xxclass::xxfunc()函数打断点。

info

查看断点/进程信息,每个断点/进程都有个序号表示,写法:

1)info breakpoints

2)info threads

delete del

删除某个断点,写法:

1)delete 3,表示删除第3个断点

disable/enable 除了直接删除断点,也可以临时让某个断点失效/生效,用法跟delete类似。
continue c 让暂停的程序继续运行
step s 单步调试,会进入函数内部
next n 运行到下一行,不会进入函数内部
backtrace bt 查看函数调用栈,每级栈都有个序号表示
frame

切换到某一级调用栈,写法:

1)frame 3,表示切到编号为3的栈顶。

list l 显示文件代码,方便知道在哪里打断点等。
print p

打印一些变量或表达式等信息,万物皆可打印。。例如:

1)print a,打印变量a的值。

2)print b.size(),打印数组b的大小。

show args 查看之前设置的命令行参数
set args 重新设置命令行参数
display 跟print类似,但是只要设置一次,之后每次在断点停下时都会自动打印出来。
watch 用于监控变量或地址的值是否发生变化,如果发生变化,程序会自动中断,这样你就知道是在哪里改变了这个变量的值了。

综上,日常调试中用到上面这些基本够用了。

3.进阶命令

gdb还可以直接调试正在运行中的进程,需要注意的是,通过命令进入后进程会挂起,可以通过使用上一节命令进行操作。

# 两种方式均可以,表示指定进程的pid,可以通过pd命令查到。
gdb -p 
gdb attach 

gdb还可以对coredump文件进行Bug定位。程序运行崩溃时一般都可以自动生成coredump文件,当大型程序崩溃时,可以通过gdb快速定位到问题代码。这里可以转到另一篇博客。

gdb还可以调试多线程程序,上小节讲到,可以通过info threads看到线程信息,实际上还可以进行进一步操作,更多操作可以移步这里。

info threads #可以看到当前有哪些线程
thread  #切换到对应的线程,其中为一个数字,是某个线程的编号

你可能感兴趣的:(c++,开发语言,bug,c语言)