调试器---GDB(Linux/Unix平台下编译型语言,C++、Go、Rust)

GDB 是C++后端开发、底层调试的核心武器

一、GDB 是什么?

GDB 全称 GNU Debugger ,是Linux/Unix平台下免费、开源、功能最强的程序调试器,完美支持 C/C++、Go、Rust 等编译型语言。

它的核心能力:

  1. 控制程序的启动/暂停/单步执行
  2. 查看程序运行时的变量、内存、调用栈
  3. 断点调试、条件触发、内存观察
  4. 定位崩溃(段错误)、死锁、逻辑错误
  5. 调试运行中的进程、core转储文件(线上排查必备)

二、前置准备:编译带调试信息的程序

GDB 无法调试纯发行版程序,编译时必须添加调试符号!

基础编译命令(C++)

bash 复制代码
# -g:生成标准调试信息
# -O0:关闭编译器优化(优化会打乱代码执行顺序,导致调试异常)
g++ -g -O0 main.cpp -o my_program

进阶推荐

bash 复制代码
# -ggdb:生成GDB专属调试信息,功能更全
g++ -ggdb -O0 main.cpp -o my_program

⚠️ 避坑:生产环境可以关闭调试符号,但测试/调试环境必须加 -g 且禁止优化


三、GDB 三种启动方式

1. 直接调试可执行文件

bash 复制代码
gdb ./my_program

启动后进入 GDB 交互模式,提示符:(gdb)

2. 调试崩溃后的 core 文件(线上崩溃排查)

程序崩溃后会生成 core.xxx 文件,直接复盘崩溃现场:

bash 复制代码
# 先开启core文件生成(执行一次即可)
ulimit -c unlimited

# 调试core文件
gdb ./my_program core.12345

3. 附加到运行中的进程(调试在线服务)

程序已经在运行,无需重启,直接附加调试:

bash 复制代码
# 先查进程PID
ps -ef | grep my_program

# 附加到进程
gdb -p 12345

四、GDB 基础核心命令

用一个简单的C++示例程序演示:

cpp 复制代码
// main.cpp
#include <iostream>
#include <vector>
using namespace std;

int add(int a, int b) {
    return a + b;
}

int main() {
    int x = 10, y = 20;
    int res = add(x, y);
    cout << res << endl;

    vector<int> vec = {1,2,3};
    return 0;
}

1. 程序控制命令

命令 简写 作用
run r 启动程序(从头运行)
start - 启动程序,暂停在main函数第一行
continue c 继续运行程序,直到下一个断点/崩溃
next n 单步执行(不进入函数内部,逐行跑)
step s 单步执行(进入函数内部,比如进入add函数)
quit q 退出GDB

2. 断点管理(调试的核心)

断点让程序在指定位置暂停,方便排查问题:

gdb 复制代码
# 1. 在指定行打断点
break 10       # b 10 → 暂停在第10行
break main     # b main → 暂停在main函数入口
break add      # 暂停在add函数入口

# 2. 条件断点(进阶)
break 10 if x==10  # 只有x=10时才触发断点

# 3. 查看所有断点
info breakpoints  # i b

# 4. 删除断点
delete 1    # 删除编号为1的断点
delete      # 删除所有断点

3. 查看代码上下文

gdb 复制代码
list          # l → 显示当前行前后10行代码
list 1,20     # 显示1-20行代码
list add      # 显示add函数的代码

4. 查看变量/内存(排查数值错误)

gdb 复制代码
# 打印变量
print x       # p x → 打印变量x的值
print res     # 打印计算结果

# 打印C++对象/容器
print vec     # 打印vector对象
print vec[0]  # 打印容器元素

# 格式化打印
print /x x    # 以十六进制打印
print /d x    # 以十进制打印

# 修改变量值(调试神器)
set var x=100 # 把x的值改成100,测试逻辑

5. 栈回溯(定位崩溃/调用链)

这是定位段错误的第一命令

gdb 复制代码
bt            # 查看函数调用栈(崩溃时看哪一行出错)
bt full       # 查看完整调用栈 + 所有局部变量(最强)
frame 0       # 切换到指定栈帧

五、实战:C++ 段错误(Segmentation fault)排查

段错误是C++最常见的崩溃(空指针、野指针、数组越界),我们用GDB快速定位:

测试代码(故意制造空指针)

cpp 复制代码
#include <iostream>
using namespace std;

void test() {
    int* p = nullptr; // 空指针
    *p = 10; // 非法访问内存 → 段错误
}

int main() {
    test();
    return 0;
}

调试流程

  1. 编译:g++ -g -O0 main.cpp -o crash
  2. 启动GDB:gdb ./crash
  3. 运行程序:(gdb) run
  4. 程序崩溃,执行:(gdb) bt full
  5. 查看崩溃代码:(gdb) list
  6. 查看可疑指针:(gdb) print p

输出结果 :直接看到p = 0x0(空指针),崩溃行一目了然。


六、C++ 专属调试技巧

GDB 对C++的类、对象、虚函数、STL、多线程有专属支持,这是区别于C语言调试的关键:

1. 调试C++ 类与对象

cpp 复制代码
class Test {
public:
    int num = 0;
    void func() { num = 100; }
};
gdb 复制代码
# 打印对象成员变量
print test_obj.num

# 调用对象成员函数
print test_obj.func()

# 调试虚函数
print *virtual_ptr # 查看虚表指针

2. 调试 STL 容器(vector/map/string)

默认GDB打印STL会很冗长,推荐直接访问元素:

gdb 复制代码
print vec.size()
print vec[0]
print map["key"]
print str.c_str()

3. 多线程调试

gdb 复制代码
info threads       # 查看所有线程
thread 2           # 切换到2号线程
break 10 thread 2  # 仅在2号线程第10行打断点

4. 观察点(监控内存修改)

排查内存被意外篡改的神器:

gdb 复制代码
watch p    # 当指针p的值改变时,程序自动暂停
rwatch p   # 当读取p时暂停
awatch p   # 读写p时都暂停

七、GDB 高级实用技巧

1. 日志输出

把调试信息保存到文件,方便复盘:

gdb 复制代码
set logging file gdb.log
set logging on

2. 跳过代码执行

调试时跳过某行错误代码,无需改源码:

gdb 复制代码
jump 15  # 直接跳转到第15行执行

3. 查看内存原始数据

gdb 复制代码
x/10i main  # 查看main函数的汇编代码
x/10w p     # 查看指针p指向的10个内存值

八、注意避坑

  1. 忘记加 -g 编译:GDB 看不到源码和变量,直接报废
  2. 开启编译器优化-O2 会打乱代码行,单步执行异常
  3. 混淆 next 和 stepn 不进函数,s 进函数,别用错

总结

对于C++来说,GDB 不是可选工具,而是必备技能

  1. 基础:run/break/next/print/bt 搞定大多数的调试场景
  2. 进阶:core文件、多线程、观察点,搞定线上崩溃
  3. C++专属:类、STL、虚函数调试,贴合实际开发

抛弃低效的cout/printf调试,熟练使用GDB后,排查bug的效率会提升10倍以上。

相关推荐
用户805533698032 小时前
主线 U-Boot 上 RK3506:和闭源 rkbin 拔河的三个隐性契约
linux·嵌入式
用户034095297913 小时前
linux fcitx 5 雾凇拼音 设置在中文输入法下仍然输入英文标点
linux
卷无止境1 天前
C++ 的Eigen 库全解析
c++
卷无止境1 天前
现代 C++特性大盘点:一门脱胎换骨的老语言
c++·后端
郝学胜_神的一滴1 天前
CMake 27:缓存变量的特性、语法、类型与实操全解
c++·cmake
Web3探索者2 天前
可视化服务器管理和传统命令行区别是什么?新手教程:Linux 运维到底该用图形界面还是 SSH 命令行?
linux·ssh
zylyehuo2 天前
Linux系统中网线与USB网络共享冲突
linux
博客18003 天前
酷宝的使用方法,超好用的免费界面库,C++、MFC可用
c++·mfc·界面库·库来帮·酷宝
郝学胜_神的一滴3 天前
CMake 026:属性体系精讲、四大作用域全解 & 实战代码落地
c++·cmake
Sokach10153 天前
Linux Shell 脚本从零到能用:一个新手的一天学习总结
linux