news 2026/9/8 23:16:11

Linux下的代码调试

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Linux下的代码调试

调试

  • 1、什么样的程序才能调试
  • 2、初识gdb和cgdb
  • 3、cgdb调试指令
    • 3.1、断点
    • 3.2、逐过程与逐语句
    • 3.3、变量的观察
    • 3.4、跳出循环的方法
    • 3.5、其它指令
  • 4、三种调试技巧
    • 4.1、watch
    • 4.2、set var
    • 4.3、条件断点

1、什么样的程序才能调试

比如我们编写一个1~100求和的小程序,编译出test.exe文件:

#include<stdio.h>intSum(ints,inte){intret=0;for(inti=s;i<=e;++i){ret+=i;}returnret;}intmain(){intstart=1;intend=100;printf("I will begin.\n");intn=Sum(start,end);printf("running done, result is: [%d-%d]=%d\n",start,end,n);return0;}

使用gdb开始调试:gdb [可执行文件名]

但是,我们会发现,除了运行代码和退出调试,我们无法对当前程序进行调试:

这是因为,我们编译test.c的时候,并没有生成调试信息。想要生成调试信息,我们编译源文件的时候就需要带上-g选项:

这样得到的可执行文件,就可以进行调试了,因为带上了调试信息。意味着只有携带了调试信息的可执行文件,才能进行调试。还记得我们在vs下编写的代码有Debug和Release两个版本的选项吗?我们可以认为,不带调试信息的可执行文件是Debug版本的软件,而携带调试信息的可执行文件是Release版本的软件

这里我们也可以发现,带上调试信息的可执行文件,文件大小相比不带调试信息的文件,变大了一些:

2、初识gdb和cgdb

使用gdb进行代码调试:gdb [可执行文件名]

这时,我们就可以展示代码、打断点、运行代码、单步调试、进入函数…输入quit可以退出调试。

但是,我们使用gdb的时候,必须手动打印出调试信息,才能观察调试过程。gdb的使用,似乎不比我们之前使用vs 2022下的调试器方便。

这时我们就可以使用另一个调试器:cgdb。执行:cgdb [可执行文件名]

cgdb下,调试控制台与代码展示是分离的,这就比较像vs 2022很方便我们观察;同时我们也能看到断点、指示运行到哪的小箭头,等等。

向上面这些调试器,本质上就是帮助我们找到问题所在的辅助工具。

3、cgdb调试指令

gdb调试太麻烦了,我们更常使用更方便的cgdb。

l: list,展示代码。

r: run,运行代码。

3.1、断点

断点的作用,是进行区域化的代码执行,帮助我们一步步缩小问题的范围,以确定问题的位置。

==b+行号: 给指定行打上断点。==我们也可以指定文件打断点。

info b: 查看断点信息。

d [断点编号]: 删除指定行的断点。

直接删除断点不是一个好习惯。我们建议保留调试痕迹,这时可以对断点进行使能
disable [断点编号]: 禁用指定断点。
enable [断点编号]: 启用指定断点。

断点的编号设置也有点意思。我们打上三个断点:

我们删除断点2,然后再在代码19行把断点加回来。我们就会发现:

代码19行的断点倒是加回来了,然而断点的编号变为了4。原来,在一个调试周期中,断点的编号是线性递增的。上面示例中,删除了断点2,又加上了一个断点,那么断点的编号就不是2了而是4。

c: continue,执行到下一个断点,如果下面没有断点了就运行到结束。

我们不仅可以指定行号打上断点,还可以给函数打上断点:
b + [函数名]: 对函数的函数体第一行打上断点。

3.2、逐过程与逐语句

之前使用vs的时候,我们使用快捷键F10就可以逐过程执行代码,即遇到函数调用直接当作语句执行;使用F11就可以逐语句执行代码,即遇到函数调用就进入函数。

Linux下的逐过程执行指令是n(next),即遇到函数调用会直接跳过函数。要想进入函数内部,我们可以执行指令s(step)

n, s指令的作用是:小范围内进行一步一步调试,进一步定位问题所在。

3.3、变量的观察

vs下有监视窗口,我们可以在监视窗口中输入一些变量,进而观察这些变量的变化情况。

Linux下cgdb中也有观察变量的指令:p(print)

还有,p不仅可以可以打印变量,也可以打印表达式:

然而p指令用得也不方便:想查看变量值必须执行一次p指令,即p指令只能临时查看变量。

我们期望指定的变量能一直显示,那就执行指令:display + [变量名]

如果我们想取消display显示的变量,执行指令:undisplay + [编号]

3.4、跳出循环的方法

假设我们排查问题的时候进入了一个循环。当我们确定这个循环没有问题的时候,我们就想跳出循环。

第一种方法,就是在循环外打一个断点,然后执行c指令

第一种方法可能比较麻烦。我们可以使用第二种方法,就是执行命令:until + [行号]。执行until语句,就会执行到指定行位置上。比如我们until指定到第11行,就可以跳出循环。

对于until,我们要注意三点:

  • until只能向下跳。如果强行向上跳,默认执行当前函数直到结束。
  • until不能跨函数。如果强行跨函数跳跃,默认执行当前函数直到结束。
  • until会自动跳过空格。

我们还有第三种方法,就是执行指令:finish。finish作用到main函数以后调用的函数,会直接执行到函数结束,返回;而finish作用到main函数则会报警告:

3.5、其它指令

bt: 查看函数调用情况。

info i: 查看与进程相关的信息。

info locals: 查看当前作用域内的局部变量。

4、三种调试技巧

4.1、watch

watch指令可以监视指定的变量,一旦变量有变化,watch就会回显变化。

比如我们监视ret:

info b查看断点,我们会发现多了一个watchpoint,专门针对的是变量ret:

ret在Sum函数中自然是不断变化的。当ret变化时,watch就会回显ret的变化:

那么watch的作用就很明显了:watch可以用来对比变量变化的前后关系。其实watch还有一个作用,那就是监视不能被改变的变量,常用于监视不能随意改变的标志值,以及指针。

4.2、set var

我们对上面的求和小程序做一点改动,使得Sum既可以求1 ~ 100的和,也可以求-1 ~ -100的和:

#include<stdio.h>intSum(ints,inte){intflag=0;//int flag = -1;//int flag = 1;intret=0;for(inti=s;i<=e;++i){ret+=i;}returnret*flag;}intmain(){intstart=1;intend=100;printf("I will begin.\n");intn=Sum(start,end);printf("running done, result is: [%d-%d]=%d\n",start,end,n);return0;}

运行上面代码,发现结果为0,不是我们的预期值。调试发现,flag被设置成了0。

当前我们验证问题的做法是:退出调试,修改代码,重新调试,以验证确实是flag出现了问题。可是这样做太麻烦了。

这时我们就可以使用set var指令:


set var的作用是方便我们验证问题的原因,应用于:

  • 有标志值的地方(flag)
  • if的条件上。比如某段代码中,程序执行始终不进入其中一个if判断语句,这时我们就可以使用set var修改if的判断条件。

4.3、条件断点

在一个循环周期中,我们发现前面很多步操作都没问题,就是某几步循环出现了一些小毛病。所以我们期望跳过正常的循环操作,定位到不正常的循环操作。这时我们就可以使用条件断点

对于上面的循环,假设前29次循环正常,第30次循环出现了问题。那么我们就需要定位到第30次循环,执行:b 12 if i==30。接着continue到下一个断点,我们就会发现,此时i确实变为了30,我们就来到了第30次循环。

条件断点的存在,使得我们能够进行符合某种条件的Debug。

当前12行断点不存在,我们才执行上面的语句。那要是12行断点已经存在了呢?执行condition [断点编号] i==30

温馨小提示


我们可能会遇到,调试时乱点了什么东西,之后调试命令行就什么也打不出来了。这时我们只需按i,即可恢复。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/4 14:50:23

奇安信笔试题复盘:路径遍历与Java数组引用陷阱解析

1. 笔试题的整体设计思路与考察逻辑1.1 一份试卷的结构&#xff1a;Java、安全、Linux、算法的组合逻辑奇安信2019春招笔试题&#xff08;二&#xff09;给我的第一印象是&#xff1a;这不是一份纯粹的技术刷题卷&#xff0c;而是一份“安全岗基本功体检表”。那段时间我在帮准…

作者头像 李华
网站建设 2026/9/5 20:49:20

微信小程序商城实战:小米商城增删改查毕设项目

微信小程序商城项目实战&#xff1a;手把手搭建小米商城&#xff0c;增删改查全流程&#xff0c;毕设面试两不误这次我们直接开干一个微信小程序商城项目&#xff0c;以小米商城为原型&#xff0c;从零搭建前端界面、后台管理系统&#xff0c;并完整实现商品增删改查、用户登录…

作者头像 李华
网站建设 2026/9/5 19:30:32

LangChain实战指南:从核心概念到RAG与Agent工程落地

最近不少读者问我&#xff1a;LangChain 版本更新这么快&#xff0c;社区资料又杂&#xff0c;到底该怎么学才不踩坑&#xff1f;这个问题问得很实在。我见过不少团队把 LangChain 当成“调用大模型的 HTTP 封装”来用&#xff0c;结果项目一复杂就发现到处都是坑&#xff1a;P…

作者头像 李华
网站建设 2026/9/5 21:54:09

移动平均模型MA:用“意外”预测时间序列的量化利器

如果你刚开始接触量化交易里的时间序列建模&#xff0c;大概率会被“MA模型”这个词搞晕。技术分析里有 MA5、MA10 均线&#xff0c;AI 圈最近也天天聊模型量化&#xff08;比如 INT8 压缩&#xff09;&#xff0c;而统计学里还有一个 Moving Average Model。同样是“MA”&…

作者头像 李华
网站建设 2026/9/5 14:41:24

长时程任务为何总翻车?Agent工程化闭环的四个技术瓶颈与解法

最近&#xff0c;投资人 Chamath 的一句评论在 AI 圈里传得很快&#xff1a;长时程任务仍是笑话&#xff0c;AI 将陷入幻灭低谷。这句话大概率会让不少正在做 Agent 产品的人感到冒犯&#xff0c;但稍微冷静一点&#xff0c;就会发现它戳中了当前 AI 应用最疼的地方。过去一年&…

作者头像 李华
网站建设 2026/9/6 10:16:22

交通灯检测未标注数据获取与利用:从数据集挖掘到伪标签训练

简介&#xff1a;本资源是面向计算机视觉与智能交通领域研究者的交通灯检测基础数据集&#xff0c;适用于目标检测模型训练、信号灯状态识别算法验证及CCF BDCI相关赛题备赛。数据集包含2000个原始采集样本&#xff0c;其中1997张JPG格式图像覆盖城市道路、交叉口、不同光照与天…

作者头像 李华