当前位置: 首页 > news >正文

【Linux 学习计划】-- Linux调试工具 - gdb cgdb

目录

先导概念 debug && release && -g 选项

gdb 的操作指令

cgdb

debug 的相关建议

结语


先导概念 debug && release && -g 选项

首先我们需要知道的是,软件开发中有两种模式,一种是debug,一种是release

这两种的区别在于,release会优化,并且不能调试,且这是给用户用的模式,所以我们测试也是用的这个模式

而debug模式则是用来检查代码逻辑,检查代码错误的,这其实是给程序员用的

而我们的debug为什么可以调试而release不能呢?本质上是因为,debug版本的可执行文件会加上对应的调试信息(而release没有调试信息,所以就不能调试)

同时,我们的release也是不需要这些调试信息的,试想一下,将调试信息给用户,是让用户自己调吗?浪费带宽等资源传一些没用的数据?这不现实

而我们在Linux中,当我们使用了gcc或者g++时(下文统一用gcc的代码做演示,因为两者都差不多),默认用的就是release,而如果要转换成debug模式的话,我们只需要在gcc后面加上-g选项即可

如下图:

(这是默认也就是release的makefile)

(这是debug的makefile):

下图,我们可以明显看到大小是不一样的,上文说了,这是由于有调试信息的存在

我们通过readelf -S 去查,筛选出debug信息时也能发现,确实只有debug的版本有对应的调试信息,而release版本查出来是空的

gdb 的操作指令

首先,我们gdb的操作是针对可执行程序的,如下图,针对的就是可执行程序:

另外,gdb是系统默认自带的,所以不需要下载安装,直接用即可

接下来就是操作指令

line 显示 也可以简写成 l,用法为 l 0  、  l 文件名:行数 、 l 文件名:函数名

run,也可以简写成r,直接用,表示将程序跑起来的意思

但是如果没有打断点的话,会直接把整个程序跑完

有断点则会停在断点处

这里的b 17表示在第17行打一个断点,所以 r 了之后就会停在断点处

breakpoint,打断点,也可以简写为 b,三种用法和最上面的 line / l 是一样的,这里不做解释

另外,我们的断点是有断点编号的,当我们使用info b的时候,就能看到最左边有一排数字,我们后续在disable、enable中都要使用这些编号

图例如下:

info,这个可以简写为 i,可以联合 b,表示查看断点,图例就是上面那张图的最后一个操作

info(i)还有一种用法,就是info locals,这个用法的作用的查看当前栈里的所有变量

比如我写了一段程序,里面的变量有i,a,b,count,那么info locals就会直接将所有变量的信息显示出来:

disable、enable

这两个,一个是禁用断点,一个是解除禁用

比如我有一个断点我待会儿可能还要用,但是我在这一次测试里面不会用到他,但我又不想把他删掉,所以我可以先disable + 断点编号把他禁用,下次要用我再enable + 断点编号解除禁用即可

n / next、s / step

这两个,一个是逐过程,一个是逐语句

逐过程就是,我们遇到的函数不会具体进入函数内部,会直接将该函数执行完

而逐语句就是会进入函数内部

比如我们现在运行到第20行,如果我们是n,那就会走到第21行,如果是s,那就会进入函数内部:

p / print:查看变量内容或者查看变量地址

就好像调试窗口,只不过只能敲一次指令显示一次:

但是按照 p 的做法,我们每一次想看都要敲一次指令,有点挫了,所以我们就有了下一个指令

display && undisplay

这个就相当于真正的窗口了,只不过我们display的时候,和p的用法是一样的,但是undisplay的时候,由于display会有和断点一样的编号,所以我们undisplay需要输入这样的编号:

我们还有一个需求就是,为了快速锁定项目中的问题出在哪里,所以我们需要逐断点查询

c / continue:逐断点

比如我们打了很多断点,如果说n和s都是执行一次就跳到下一条代码,那么 c 就是跳到下一个断点处

还有就是,当我们只想快速看看当前函数能否达到相应的效果,就是想快速看看时,我们就可以用下面这一条指令

finish,直接用,如下:

如果我们在一个函数中,进入了一个很大的循环,出不去了,或者说就是想单纯跳到第几行代码,中间的全部给我执行一遍,那么我们就可以用这条指令:

until,后面要加行号,表示你要跳到第几行

set var

比如我们在循环中,可以直接用 set var 将某一个变量设置为某一个值

或者是我们可能一个项目,就某一个值跑不了,我们就可以设置成这个值看看

但是我们需要知道的一点是,set var之后的值可能是错的,如上图,本来应该是sum == 5050,但是我们直接set var之后,sum的结果就不对了,需要注意

bt,这是个小命令,是用来查看堆栈的:

cgdb

先解释一下,cgdb相当于是gdb的加强版

但是默认不会自动安装,所以需要我们手动安装:

Ubuntu:sudo apt install cgdb

centos:sudo yum install -y cgdb

所有用法和gdb是一样的,照着用即可

debug 的相关建议

叠个甲,这只是我个人认为可以试一试的方法,如果大佬有更舒服的用法可以在下面评论区分享一下,主包也想进步啊

首先我们的gdb只是一个工具,是帮助我们找出问题所在的,但是真正解决问题的时候,还是要靠我们程序员自身

而当我们遇到问题的时候,可以先使用一眼盯帧法(我的眼睛就是尺),可能就是一些语法问题,肉眼就能看出来

接着如果看不出来,就可以用打印法,在相关地方printf或者cout一些内容,这样基本就能解决大部分问题了

最后实在不行了,再使用cgdb或者gdb,但是使用同样有技巧,就是,我们可以用断点+二分的方法快速判断出问题出在哪里(比如有1000行代码,我们先在500行打个断点,看看前500行能不能跑,没问题就是后500行的问题,就接着在750行打断点,以此类推,快速锁定

最后到地方了,再用一眼盯帧法,打印法,或者干脆就是n,s,c,display一步步往下看

结语

这篇文章到这里就结束啦!!~( ̄▽ ̄)~*

如果觉得对你有帮助的,可以多多关注一下喔

http://www.xdnf.cn/news/625609.html

相关文章:

  • 怎么开发一个网络协议模块(C语言框架)之(二) 数据结构设计
  • RabbitMQ核心特性——重试、TTL、死信队列
  • python项目和依赖管理工具uv简介
  • OpenLayers 加载鼠标位置控件
  • git常用操作命令
  • 用本地大模型解析智能家居语音指令:构建一个离线可用的文本控制助手
  • vitepress | 文档:展示与说明只写一次,使用vitepress-deme-preview插件
  • 力扣HOT100之回溯:46. 全排列
  • juc面试题
  • LumaDot (亮度可调的屏幕圆点)
  • 分布式消息中间件基础
  • 网络协议与通信安全
  • Oracle 19c DG备库报错ORA-00313、ORA-00312、ORA-27037
  • 【Linux仓库】权限的量子纠缠:用户/组/other如何编织Linux访问控制网?
  • el-form 使用el-row el-col对齐 注意事项
  • 从碎片化到集成化:Profibus转Profinet网关引领设备管理数字化转型
  • 【TypeScript】知识点梳理(四)
  • 5月24日day35打卡
  • qiankun解决的问题
  • ABC406E 题解
  • python中Web框架Flask vs FastAPI 对比分析
  • 一个开源的 Blazor 跨平台入门级实战项目
  • 红黑树简单模拟实现
  • 随机森林(Random Forest)学习
  • ES的Refresh、Flush、Merge操作对性能的影响? ES如何实现近实时(NRT)搜索? ES聚合查询的Terms和Cardinality区别?
  • R基于多元线性回归模型实现汽车燃油效率预测及SHAP值解释项目实战
  • TDengine 高可用——双活方案
  • 爬虫实战之爬微博图片:xpath的具体运用
  • maven 3.0多线程编译提高编译速度
  • C++类型转换