Linux-cgdb

目录

1.cgdb

2.cgdb调试时的指令


1.cgdb

好,那么咱们今天来学习Linux中的调试器-cgdb:

那么咱们在学习这个之前,咱们必须得了解一件事情:

cgdb调试的时候,必须得使用debug版本,不可以使用release版本

(1)你直接用gcc/g++ -o code code.c编译出来的程序,是Release 版本

  • 特点:体积小、运行快,但不带任何调试信息
  • 后果:用 GDB 打开时会提示 (no debugging symbols found) ------ 就像给你一本没有页码和目录的书,你根本没法定位到具体某一行代码。

(2)怎么编译出可调试的 Debug 版本?

需要加 -g 参数:gcc -o code-debug code.c -g

  • 加了 -g 后,编译器会在可执行文件里插入调试信息(比如行号、变量名、函数名)。
  • 代价:可执行文件体积变大(图里对比:code 8520 字节,code-debug 9752 字节)。
  • 验证:用 readelf -S code-debug | grep -i debug 能看到一堆 .debug_* 段,这就是调试信息的藏身之处。

(3)ELF 格式是什么?

图里提到 ELF 64-bit LSB executable,大白话讲:

  • 可执行文件不是一堆乱码,而是有固定格式的「数据包」,Linux 下这个格式就叫ELF
  • 它里面分了很多段:代码段、数据段、调试段等,readelf 就是用来拆开这个包看里面结构的工具。

Debug vs Release 在整个开发流程里的角色:

(1)Debug 模式(开发阶段用)

  • 给谁用:程序员自己。
  • 作用:方便调试、定位 Bug,能一步步看代码执行、变量变化。
  • 缺点:体积大、运行慢,因为带了一堆调试信息,给用户用完全没必要,还会暴露代码细节。

(2)Release 模式(上线 / 测试 / 给用户用)(不支持调试)

  • 给谁用:测试人员、最终用户、老板。
  • 作用:去掉所有调试信息,优化运行速度、减小体积,是最终交付的版本。
  • 特点
    • 测试人员测的就是这个版本(因为用户最终用的也是它)。
    • 给用户的软件必须是 Release 版,不然体积太大,还可能泄露源码。
    • 老板要的是能赚钱、能上线的版本,肯定是 Release 版。

(3)完整开发流程

开发写代码(Debug 模式)→ 提交给项目经理审核 → 合并代码 → 联合测试(用 Release 版测)→ 没问题就上线推广。

  • 开发时:用 Debug 版,方便自己调试 Bug。
  • 测试时:用 Release 版,模拟用户真实环境。
  • 上线时:只发 Release 版,保证性能和体积。

用生活例子类比:

把写程序比作做奶茶

  • Debug 模式:就是你在店里试做的版本,杯上贴满便签,记录糖放了多少、茶煮了几分钟、奶盖厚度多少,方便你调整口味(调试 Bug),但给顾客喝肯定不行,太乱、太丑。
  • Release 模式:就是最终卖给顾客的成品,包装干净、口感最优、体积刚好,没有任何多余的便签(调试信息),顾客喝着舒服,你也能卖钱。

总结:

  • 默认编译 = Release 版:没法调试,适合上线给用户。
  • -g 编译 = Debug 版:能调试,适合开发阶段自己用。
  • 开发用 Debug,测试 / 上线用 Release:这是行业通用规则,既保证开发效率,又保证产品质量。
  • 体积差异:Debug 版因为带调试信息,会比 Release 版大一些,这是正常的。

2.cgdb调试时的指令

那么l(或者不是数字1,是字母l,list):罗列你的代码

l 0:第0行居中,然后上下文显示代码

b:(breakpoint):打断点

b 20:给第20行打断点

r(run):开始调试

但是在这里,我需要强调一件事情,就是这个r跟start的区别

维度 r (run) 指令 start 指令
核心行为 直接启动程序,无默认断点,程序会「一口气运行到结束」(除非你手动设了断点) 启动程序时自动在main函数第一行设临时断点,程序启动后立刻暂停(不会直接退出)
对你的实际影响 你执行r后,程序直接跑完sum函数、打印 10、退出进程,后续再执行r/until就会提示「The program is not being run」 你执行start后,程序停在int start=6;这一行,进程处于「运行但暂停」状态,此时执行until 13/next等指令都不会报错
重复执行的表现 第一次执行后进程退出,第二次执行会提示「程序已启动」,无论选 y/n 最终都无活跃进程 重复执行会自动终止旧进程,重新启动并停在main入口,始终有活跃进程,不会提示无进程
适用场景 1. 想快速验证程序整体运行结果(比如只看最终输出 10);2.已手动设断点(如b main)后,启动程序并停在断点处 1. 新手分步调试(逐行看代码执行);2. 避免程序直接退出导致的调试指令报错(你遇到的核心问题)
调试流程复杂度 高:需要手动设断点才能避免程序直接退出,否则易出现「无进程」报错 低:自动设临时断点,开箱即用,新手友好

就是r是一口气全部执行完的,那么一口气全部执行完了,你就没有这个进程就退出了,那么自然后面再执行until,n,s,这样的指令也就没有办法进行了。但是你要是想不让程序一口气的执行退出,你就可以先打断点,然后再r,就会停在那个断点的地方。或者是采用start的指令,就是可以自动的停在main函数那里,之后你按until,n,s指令也就是没有任何问题了。

你遇到的「执行r后再执行指令提示无进程」,本质是:

  • r就像你按了播放键,电影(程序)直接从头播到尾,播完就结束了,再按播放键(r/until),播放器(GDB)会告诉你「没电影可播了」;
  • start就像你按了播放 + 暂停键,电影刚开场(main函数开头)就暂停,此时你可以随意快进(until)、逐帧看(next),播放器始终有「正在播放的电影」,不会提示无内容。

包括你的finish也无法使用

那么咱们现在来打断点:

那么咱们现在打了这些断点,然后咱们查看一下这些断点

查看断点就是使用info b指令,并且,咱们可以发现断点前面的Num就是序列都是呈线性递增的关系的。然后咱们r,就是会跳到对应的第一个断点处了。

这里还需要注意一点,你如果说想重新调试的话,你直接再按一次r即可。

实现断点之间的跳跃(一个断点运行到下一个断点):用c(continue)

那么咱们接下来介绍两个指令:

n(next):就是程序逐行运行(单步执行,不进入函数内部)。

s(step):进入函数内部,是进入到函数内部的不包含

这个的第一行,也就是这个图片里面的第四行。然后你按回车也好,按s,n都可以,因为这个是在函数内部走的代码,所以只要不遇到又一个函数,你在这个里面s,n均可。

p 变量 (打印变量的值) 就是查看变量是如何变化的

但是不推荐,因为这样太麻烦了,咱们可以直接使用display,就是起到了监视窗口的功能,比如display result,这个display是,你添加监视之后,下面的每一次n,s,这个监视的变量都会存在,但是p不一样,p打印的变量只会存在于一次,就是你再下次n,s之后就会消失了。

而undisplay +序列号,就可以取消掉经常显示的那个变量(就是display的那个变量)

注意要是序列号,可不是undisplay的变量名

还有一个就是你如果说进入了一个函数之后,但是你不想执行这个函数了,你只想要结果,那么你可以在函数内部,直接finish即可完成。

watch:

啥是 watch?

简单说:watch就是给变量设个 "盯梢的",只要这个变量的值被修改,程序就会立刻暂停,告诉你 "有人改了这个变量!"。比如你怀疑某个变量被莫名改了值,不用逐行找,用 watch 一监控就知道。

怎么用?(大白话步骤)

  1. 用 CGDB 启动程序:cgdb 你的程序名(比如cgdb test.out);
  2. 先在变量初始化的地方打断点(比如b main),然后run运行程序,让程序停在断点处;
  3. 输入watch 变量名(比如watch count),回车后会提示 "Hardware watchpoint 2: count",说明监控成功;
  4. 继续continue运行程序,只要count的值被改,程序会立刻暂停,还会告诉你 "旧值是 X,新值是 Y"。

那么咱们可以看到如图所示

注意你要写的是watch count

比如你有一些变量不应该被修改,但是你怀疑它修改而导致了问题,那么就可以去watch它,如果变化了,就会通知你

set var------ 调试时 "强行改值",不用重新编译

啥是 set var?

调试时发现某个变量值错了,想试试 "把它改成正确值后程序会不会正常",总不能改代码、重新编译吧?set var就是干这个的 ------ 直接在调试时修改变量值,实时验证你的猜想。

怎么用?(大白话步骤)

  1. 程序停在断点处(比如停在循环里);
  2. 输入set var 变量名=新值(比如set var count=10);
  3. 输入print 变量名(比如p count),确认值已经改成 10 了;
  4. 继续continue运行,程序就会用这个新值执行。

可以改各种类型的变量:整数、字符串、数组元素(比如set var arr[0]=5)都能改。

添加条件断点 ------ 只在 "满足条件时" 暂停(条件满足时触发这个断点,没满足之前会当断点不存在)

啥是条件断点?

普通断点b 行号会让程序每次走到这行都暂停,但有时候我们只想 "当某个条件满足时才暂停"(比如循环跑 100 次,只在 i=50 时暂停),这时候就用条件断点,不用一次次continue跳过,省超多时间。

怎么用?(大白话步骤)

  1. 输入b 行号 if 条件(核心格式);
  2. 比如b 8 if i==5(第 8 行,只有 i 等于 5 时才暂停);
  3. run运行程序,只有条件满足时才会停在这行。

disable +Num(断点序列号),是禁用掉这个断点

可以发现,禁用掉的这个断点的Enb是n,就代表不可用这个断点。然后正常的可用断点是红色的,而不可用的断点是黄色的。

好了,那么咱今天的cgdb就讲到这里了。

相关推荐
小峰编程1 小时前
二进制安装Nginx——详细
linux·运维·服务器·nginx·云原生
无限码农1 小时前
2.1 网络编程 异步网络库zvnet
服务器·网络·php
九硕智慧建筑一体化厂家1 小时前
什么是楼宇自控?全面解析楼宇自控与楼宇自控系统的作用
大数据·运维·人工智能·网络协议·制造
丿罗小黑1 小时前
【2026】Openclaw使用经验(阿里云服务器)
运维·服务器·chrome
桌面运维家2 小时前
Linux VHD 虚拟磁盘更新指南:高效管理与优化
linux·运维·数据库
在屏幕前出油2 小时前
02. FastAPI——路由
服务器·前端·后端·python·pycharm·fastapi
进击切图仔2 小时前
Linux 挂载操作
linux·运维·服务器
武汉禹力自动化科技2 小时前
ABB气动执行器DP020SR / DP050SR / DP110SR区别详解 | 禹力自动化科技有限公司
运维·科技·自动化
炽天使3282 小时前
龙虾尝鲜记(4)——Ubuntu 笔记本无头服务器全配置
linux·服务器·ubuntu