跳到主要内容
极客日志极客日志面向AI+效率的开发者社区
首页博客我的书AI学习GitHub 精选镜像AI 生图工具UI配色美学关于
搜索内容 / 工具 / 仓库 / 镜像...⌘K搜索
注册
博客列表
C++

Linux 下调试 C/C++ 程序的核心命令:GDB 基础与进阶

GDB 是 Linux 下调试 C/C++ 程序的核心工具。编译时需添加-g 选项以包含调试信息。 GDB 的基本操作,包括启动调试、查看源代码、设置断点、单步执行(next/step)、查看变量值及修改变量。进阶功能涵盖条件断点、监视变量变化(watch)以及使用 cgdb 提升体验。通过二分法定位问题区域,结合栈帧信息和局部变量分析,可有效解决程序逻辑错误。

baireiraku发布于 2026/2/25更新于 2026/9/671 浏览
Linux 下调试 C/C++ 程序的核心命令:GDB 基础与进阶

软件发布模式主要有 debug 和 release 两种。以 VS2022 为例,一般程序员在写代码开发期间处于 debug 模式,当软件自测通过发布时是以 release 模式来发布的。

Windows 中在 VS 编好的程序默认在 debug 模式下是可以直接调试的,但在 Linux 下编译好的程序能否直接进行调试?答案是不能!下面举个例子。

随便找一个可执行程序演示一下:

gcc/g++默认的工作模式是 release 模式,编译好的代码不能直接进行调试。所以想要让自己的程序能够在 debug 模式下调试,需要在程序编译进行翻译的时候,需要加一个 -g 选项:

一句话总结:在 Linux 下程序要进行调试,必须处于 debug 模式,也就是在编译时加上 -g 选项。再说得直白一点,gdb 调试就是要调试携带调试信息的可执行文件!

1、快速认识 gdb

进入 gdb 开始调试:gdb 可执行文件 退出 gdb 环境:quit

进入 gdb 环境后想要查看程序的源代码输入 list(简写为 l 即可)并回车;也可以输入 l 行号,表示从某行开始展示源代码。使用 l 指令只能显示一部分源代码,若想显示剩余部分源代码按回车键即可。

(此处展示源代码列表)

也可以 l 指定文件名 查看指定文件的源代码。

打断点:b 行号

将断点打在第 19 行再输入 r(run)运行,就能直接停到断点处了。

想要直接将程序跑完,输入 c(continue)就可以了:

(此处展示程序运行结果)

2、解决 gdb 难用的问题

前面已经演示了 gdb 的基本使用,但是使用的过程中会发现 gdb 太恶心人了,想查看源代码结果还与调试信息混在一起了,所以后面的演示统一使用 cgdb,cgdb 和 gdb 是一模一样的,但是 cgdb 可以动态呈现我们的源代码。

用于测试 gdb 使用方法的样例代码:

#include <stdio.h>
int Sum(int s, int e){
    int result = 0;
    for(int i = s; i <= e; i++){
        result += i;
    }
    return result;
}
int main(){
    int start = 1;
    int end = 100;
    printf("I will begin\n");
    int n = Sum(start, end);
    printf("running done, result is: [%d-%d]=%d\n", start, end, n);
    return 0;
}

cgdb 在默认环境下是没有安装的,下面推荐直接安装:

Ubuntu:sudo apt-get install -y cgdb Centos:sudo yum install -y cgdb

安装完成再重新打开使用(cgdb 可执行文件)

可以看到,上面是代码界面,下面是 debug 界面,更加方便我们调试代码了;想要退出还是一样输入 quit 回车

3、学习并使用 gdb 命令

3.1 运行命令

r(run):r 就类似于 vs2022 当中的快捷键 F5,意思是调试并运行,直接将程序从入口运行到程序结束。

(此处展示运行结果)

3.2 打断点和删除/禁用断点

但通常我们习惯上不会直接让程序直接运行结束,而是让其停到程序的某个位置,这时候就需要给程序打上断点

b(break):b 就是 vs 中的 F9,给程序的指定行号打上断点用法:b 源文件:行号 b 源文件:函数名 b 行号

(此处展示打断点)

打好断点之后输入命令 info b,就可以查看所打的断点的信息以及编号

(此处展示断点信息)

使用过的断点不想用了也可以删除,输入 d 断点编号 回车即可删除想删除的断点(d+ 行号删除不了断点,必须输入 d+ 断点编号)

(此处展示删除断点)

断点编号是以线性递增的形式往上加的,即如果打了三个断点但都删除了,接下来再打新的断点那断点编号为 4;如果退出 gdb 再重新进入才会从 1 开始递增。

断点是可以使能的! 也就是说断点使用过后可以不删,直接禁用即可

为什么要有禁用功能而不直接删除?因为有时候比如打了 10 个断点,调试完成后也许要去掉其中 6 个断点,但是如果把断点删除了下次要再调试时会导致自己忘记之前打过的断点在哪。所以这个使能效果还是很有用的,他能帮助记录下之前调试的痕迹!

disable:disable 断点编号 表示禁用断点 enable:enable 断点编号 表示给断点使能

(此处展示使能状态)

图中黄色框内 y 表示该断点是否被使能,如果为 n 即表示未被使能,也就是该断点此时已经被禁用

(此处展示颜色区别)

从上图可以看出,被使能的断点显示行号是红色的,未被使能的断点行号显示为黄色

3.3 逐过程和逐语句

使用 vs 时打完断点,运行程序到断点处停下来时就可以按 F10(逐过程)F11(逐语句)了

gdb 中逐过程和逐语句分别为:

n(next):逐过程(代码一行一行执行,遇到函数时会直接跳到下一行代码,不进入函数内部) s(step):逐语句(一行一行执行,遇到函数时会进入函数内部)

(此处展示逐语句)

当输入 s 进入 sum 函数内部时,如果测试到函数内部某个逻辑没有问题想直接退出函数,可以输入 finish 回车,直接跳回到进入函数的入口行

这里说明一下为什么进入函数前是在第 19 行而函数退出时又是 19 行:因为该行代码是两个调用,一个是 Sum 函数,一个是将 Sum 函数的最终结果返回给 n,所以直接 finish 退出函数时还是在第 19 行。

p : 输入 p 变量名 可以查看一个临时变量:

上面提到了 19 行的代码,将 Sum 的返回值赋给 n 是两个步骤,通过下图就可以验证:当退出 Sum 函数时箭头指向 19 行,然后输入 p n 来查看 n 的值,可以看到此时 n 为一个随机数;当程序再往下运行时再查看一次 n 的值,这时 n 就为 Sum 函数计算后的返回值了

(此处展示变量值变化)

3.4 gdb 命令集合
命令作用说明样例示例
list/l显示源代码,从上次位置开始,每次列出 10 行list/l 10
list/l 函数名列出指定函数的源代码list/l main
list/l 文件名:行号列出指定文件的源代码list/l mycmd.c:1
r/run从程序开始连续执行run
n/next单步执行,不进入函数内部,逐过程 F10next
s/step单步执行,进入函数内部,逐语句 F11step
break/b [文件名:] 行号在指定行号设置断点break 10
break test.c:10
break/b 函数名在函数开头设置断点break main
info break/b查看当前所有断点的信息info break
finish执行到当前函数返回,然后停止finish
print/p 表达式打印表达式的值print start+end
p 变量打印指定变量的值p x
set var 变量=值修改变量的值set var i=10
continue/c从当前位置开始连续执行程序continue
delete/d breakpoints删除所有断点delete breakpoints
delete/d breakpoints n删除序号为 n 的断点delete breakpoints 1
disable breakpoints禁用所有断点disable breakpoints
enable breakpoints启用所有断点enable breakpoints
info/i breakpoints查看当前设置的断点列表info breakpoints
display 变量名跟踪显示指定变量的值(每次停止时)display x
undisplay 编号取消对指定编号的变量的跟踪显示undisplay 1
until 行号执行到指定行号until 20
backtrace/bt查看当前执行栈的各级函数调用及参数backtrace
info/i locals查看当前栈帧的局部变量值info locals
quit退出 GDB 调试器quit

4、调试的本质(过程)是什么?

  • 找出问题所在
  • 查看代码上下文(查看代码或者变量的值)
  • 解决问题

断点的本质:是把代码进行块级别的划分,在不清楚程序出错的位置的情况下,以块为单位来快速定位区域,方便查找问题所在。

在代码只有二三十行时给程序分成四等分并打上三个断点,输入 r 回车让程序运行至第一个断点处,如果没有发生错误,说明问题不是出在第一个区域,依次类推,让程序一块块的执行,直到找到出错的位置。

在调试代码时,通常会用二分查找的方式找到程序的问题所在:

  • 先在程序中间位置打断点;
  • 运行到断点,判断'问题出在断点之前,还是之后';
  • 重复缩小范围,直到定位到具体的出错行 / 逻辑。

在 vs 中,让程序从一个断点处执行到另一个断点位置停下,要按 F5,而 gdb 中则是输入:

c(continue):输入 c 回车,可以让程序从一个断点执行到下一个断点停止。

(此处展示继续执行)

  • 如果确定问题出现在某一行,并且该行调用了某个函数,这时候就可以进入函数内部,输入 finish 并回车,直接将该函数跑完,查看问题是否出现在该函数内部
  • 如果确定问题就出现在该函数体内,但是循环部分未出现问题,可以输入 until 行号 回车直接执行完该部分

finish:直接执行完所调用的函数,查看问题是否出现在函数内部 until:until 行号,表示如果确定函数内部某部分没有问题,可以将局部区域快速执行完

当调试过程中已经将问题出现的范围缩得很小时,就可以通过检查一些变量的值、地址等信息,再推理出问题的根本所在

前面已经提到可以通过 p 变量名 来查看代码运行到某处时某个变量的信息,但这个方法不足以完成监视人任务

想要做到如 vs 的监视功能,可以使用以下命令:

display:display 地址/变量 表示查看变量的值或者地址等信息 undisplay:undisplay 编号 表示删除该编号想要查看的信息 info locals:info locals 表示进入一个函数时查看还函数内部所有临时变量的值

(此处展示监视变量)

这里注意一下:display 时该信息前都会有一个编号,和断点类似,用 undisplay 删除查看的信息时一样要通过信息编号来删除

5、进阶用法

5.1 watch

watch:watch 变量名 表示执行时监视⼀个表达式(如变量)的值。如果监视的表达式在程序运行期间的值发生变化,GDB 会暂停程序的执行,并通知使用者

(此处展示 watch 效果)

在调试过程中某个值会不断发生改变,watch 该变量 就可以监视该变量的值在变化前后的对比。

想要删除它们也是像删除断点一样 d 编号 即可。

watch 最重要的点在于:如果你有一些变量不应该改,但是你怀疑是因为它被修改而导致了问题,你可以 watch 它,如果变化了,就会通知你

5.2 set var

set var:set var 变量名=n 表示在调试过程中发现是某个变量导致出现问题,直接给该变量赋值再调试,如果赋值后发现没有错说明就是该变量导致出错,这时再去修改源代码,就不需要先去修改源代码再重新编译再调试了

(此处展示 set var 效果)

图释:本来计算结果是 5050,但是由于 flag 为 0 所以导致结果变为 0;所以此时用 set var flag=1 发现确实是因为 flag 的值有问题。所以只需要在调试时用 set var 给某个变量赋值看是否符合预期,如果是,那么这时再按此修改源代码即可。

5.3 条件断点

前面已经提到了如何打断点,以及断点使能、断点的删除。可是如果我既不想删、也不想使能断点,只想在某个条件下触发断点:

b 行号 if 变量=n:表示当某个变量的值等于 n 时触发该断点;也就是说,如果在循环内部打了一个条件断点,当程序运行时会直接停到该行,但是此时该变量的值为 n,就可以查看该变量值为 n 时其他变量的值为多少

打断点示例:

(此处展示条件断点)

使用条件断点案例:

(此处展示条件断点运行)

如果想要在该条件断点已经存在的条件下新增断点,该如何操作?

condition 断点编号 变量==n:表示给已经存在的断点新增条件

解释新增断点条件:如果已经存在一个条件断点为 i == 10,那运行程序输入 c 到达该条件处停下,那么还可以在该断点下新增条件如 i == 20,此时再输入 c 就会到达 i ==20 处停下来,也就是一个断点如果有两个条件,那么它可以分别在达到各自条件下停下来

条件断点添加常见两种方式:1. 新增 2. 给已有断点追加注意两者的语法有区别,不要写错了。新增:b (行号/文件名:行号/函数名) if i == 30 (条件) 给已有断点追加:condition 2 i==30,其中 2 是已有断点编号,没有 if

cgdb 分屏操作 ESC 进入代码屏,可按键盘上下键查看源代码;i 回到 gdb 调试屏

目录

  1. 1、快速认识 gdb
  2. 2、解决 gdb 难用的问题
  3. 3、学习并使用 gdb 命令
  4. 3.1 运行命令
  5. 3.2 打断点和删除/禁用断点
  6. 3.3 逐过程和逐语句
  7. 3.4 gdb 命令集合
  8. 4、调试的本质(过程)是什么?
  9. 5、进阶用法
  10. 5.1 watch
  11. 5.2 set var
  12. 5.3 条件断点

更多推荐文章

查看全部
  • Linux C/C++ 调试器 gdb/cgdb 实战指南
  • OpenAI 发布 GPT-4o 多模态模型及接入方式详解
  • 2026 年春晚 AI 应用解析与普通人技术风口应对策略
  • Ubuntu 24.04 深度学习环境配置:NVIDIA 驱动与 CUDA 安装验证
  • Linux 手动部署并测试内网穿透
  • LocalAI 本地推理引擎:不用 GPU 也能跑大模型
  • FunASR 离线文件转写服务开发与部署实战
  • SBUS 协议原理与实战:无人机航模机器人通信方案
  • 统一 API 接口下的多模型接入与成本优化方案
  • AIGC 产品经理的定义、职责及与 AI 产品经理的区别
  • Soft Actor-Critic (SAC) 算法详解与 PyTorch 实现
  • Web 自动化测试实战:常用函数全解析与场景化应用
  • C 语言快速排序详解与多种优化变式
  • WhisperX 快速上手指南:基于 OpenAI Whisper 的语音识别工具
  • STL map 与 multimap 核心特性及接口详解
  • OpenClaw 跨平台安装指南:Windows 与 Ubuntu
  • Java RESTful 接口开发实战指南
  • 统一模型网关实战:多模型调度与自动化数据管道构建
  • 仓库管理系统前端开发:主区域查询与重置功能
  • 电脑桌面时钟显示软件 Digital Clock 4 使用教程

相关免费在线工具

  • Base64 字符串编码/解码

    将字符串编码和解码为其 Base64 格式表示形式即可。 在线工具,Base64 字符串编码/解码在线工具,online

  • Base64 文件转换器

    将字符串、文件或图像转换为其 Base64 表示形式。 在线工具,Base64 文件转换器在线工具,online

  • Markdown转HTML

    将 Markdown(GFM)转为 HTML 片段,浏览器内 marked 解析;与 HTML转Markdown 互为补充。 在线工具,Markdown转HTML在线工具,online

  • HTML转Markdown

    将 HTML 片段转为 GitHub Flavored Markdown,支持标题、列表、链接、代码块与表格等;浏览器内处理,可链接预填。 在线工具,HTML转Markdown在线工具,online

  • JSON 压缩

    通过删除不必要的空白来缩小和压缩JSON。 在线工具,JSON 压缩在线工具,online

  • JSON美化和格式化

    将JSON字符串修饰为友好的可读格式。 在线工具,JSON美化和格式化在线工具,online