1、GDB入门:GDB是什么、GDB与Qt的关系、GDB的安装与配置、第一个GDB调试会话
1.1 GDB到底是什么?
GDB,全称GNU Debugger。说白了,就是一个让你能「看穿」程序运行过程的工具。
我刚开始做C++开发那会儿,调试全靠printf。满屏的打印语句,改完还得重新编译。后来一个老同事跟我说:「你试试GDB吧,省得你天天改代码。」一试,真香。
GDB能做什么?
- 让程序在任意位置停下来(断点)
- 查看变量当前的值
- 单步执行,一行一行看代码怎么跑
- 程序崩溃时,告诉你崩溃在哪一行
- 甚至能修改运行中的变量值
嗯,你可以把它理解成程序的「CT机」。不用开刀,就能看到内部结构。
1.2 GDB与Qt的关系
很多Qt开发者有个误区:Qt程序用Qt Creator调试就够了,GDB是命令行工具,太原始。
其实Qt Creator的调试器底层就是GDB。你点那个绿色小三角旁边的「调试」按钮,背后调用的就是GDB。只不过Qt Creator给它套了个图形界面。
我在项目中遇到过几次Qt Creator卡死的情况——信号槽断点太多,IDE直接崩溃。但GDB命令行稳如老狗。你想想看,关键时刻,命令行反而更可靠。
核心认知:Qt Creator是GDB的「图形化外壳」。学会GDB命令行,等于掌握了调试的「底层能力」。遇到IDE搞不定的场景,你还能用GDB硬核解决问题。
另外,Qt的信号槽机制在GDB里调试起来有点特殊。信号槽调用链很长,堆栈信息看着眼花。但别怕,后面我会专门讲怎么在GDB里看清信号槽的调用关系。
1.3 安装与配置
安装GDB其实很简单。不同系统略有差异,我列个表给你看:
| 操作系统 | 安装命令 | 备注 |
|---|---|---|
| Ubuntu/Debian | sudo apt install gdb |
一般系统自带,更新一下即可 |
| CentOS/RHEL | sudo yum install gdb |
或者用dnf |
| macOS | brew install gdb |
需要签名,否则可能跑不起来 |
| Windows | MinGW或MSYS2 | 建议用Qt自带的GDB |
安装完验证一下:
gdb --version
看到版本号就说明装好了。
小提示:我个人习惯在~/.gdbinit里写一些配置。比如设置断点显示风格、开启历史记录等。后面章节我会分享我的配置文件。
1.4 第一个GDB调试会话
光说不练假把式。我们来跑一个真实的Qt程序调试。
先写个简单的Qt程序:
// main.cpp
#include <QApplication>
#include <QPushButton>
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
QPushButton btn("点我");
btn.show();
int result = app.exec();
return result;
}
编译的时候注意,要加-g选项,保留调试信息:
g++ -g -o myapp main.cpp -I/usr/include/qt5 -lQt5Widgets
或者用qmake/qmake,记得在.pro文件里加:
CONFIG += debug
好,现在开始调试:
gdb ./myapp
你会看到GDB的提示符:(gdb)。
我们来设个断点:
(gdb) break main
Breakpoint 1 at 0x4007a4: file main.cpp, line 7.
然后运行程序:
(gdb) run
程序会在main函数入口停住。这时候你可以:
next(或n):执行下一行step(或s):进入函数内部print btn:查看btn对象continue(或c):继续运行直到下一个断点
试试看:
(gdb) n
QPushButton btn("点我");
(gdb) n
btn.show();
(gdb) print btn
$1 = {<QAbstractButton> = {<QWidget> = {<QObject> = {_vptr.QObject = 0x555555758d20 <vtable for QPushButton+16>}, ...}, ...}, ...}
看到没?Qt对象的内部结构一览无余。这在排查信号槽连接、属性设置等问题时特别有用。
注意:第一次调试Qt程序,可能会遇到「Missing separate debuginfos」的提示。这是因为系统没有安装Qt库的调试符号。可以安装对应的debug包,或者忽略——大部分情况下不影响调试你自己的代码。
1.5 知识体系总览
下面这张图,是我对GDB入门阶段知识结构的梳理:
1.6 避坑指南
最后分享几个我踩过的坑:
- 忘记加-g编译:我曾经排查一个崩溃问题,搞了半小时才发现编译时没加-g。GDB只能看到地址,看不到源码行号。白忙活。
- Release版调试:Qt的Release模式默认会优化代码,变量可能被优化掉,断点可能跳来跳去。调试时务必用Debug模式。
- 信号槽断点:在connect语句上打断点,你会发现程序根本不停。因为connect是在运行时动态连接的。要在槽函数内部打断点。
我的习惯:每次开始调试前,先跑一遍info sharedlibrary,看看所有加载的库。如果Qt库没加载调试符号,我会提前装好对应的debug包。省得调试到一半发现看不到Qt内部变量。
好了,第一章就到这里。GDB入门其实不难,关键是动手。打开你的Qt项目,试着用GDB跑一次,感受一下命令行调试的「掌控感」。
可可精品资料库