【Linux系统编程】Linux调试器——gdb 的基本使用

news2024/10/4 12:26:06

文章目录

  • 1. 准备工作及知识补充
    • 1.1 源文件和Makefile
    • 1.2 安装gdb并解决没有调式信息的问题
      • debug和release的了解
      • 如何解决
  • 2. gdb的基本使用
    • 2.1 显示代码
    • 2.2 设置、删除和查看断点
    • 2.3 禁用和启用断点
    • 2.4 逐语句和逐过程调式
    • 2.5 查看函数调用堆栈
    • 2.6 查看指定变量的值
    • 2.7 跳至指定行
    • 2.8 只执行完当前函数
    • 2.9 跳转到下一个断点
    • 2.10 修改变量的值
    • 2.11 退出gdb

这篇文章我们继续学习Linux中的开发工具。
经过之前的学习,我们已经能够在Linux上编写代码、运行代码和通过git管理代码了。但是如何在Linux上调式代码我们还不知道,所以今天要学的是Linux调试器——gdb 的基本使用。
在这里插入图片描述

1. 准备工作及知识补充

那要使用调式器调式,首先我们得有代码,有可执行程序。

1.1 源文件和Makefile

所以,我先来写一个代码,写一下Makefile

先写一个源文件test.c在这里插入图片描述
然后写一下Makefile
在这里插入图片描述

然后我们来编译运行一下:

在这里插入图片描述
我们发现报错了
说的是“for”循环初始声明仅在C99模式中允许,即循环变量不能在for循环里面定义
这是因为我们得gcc的版本可能比较低,不支持C99
那怎么让它支持呢?
也很简单,在Makefile里面加一点东西
在这里插入图片描述
-std=c99
然后
在这里插入图片描述
就可以正常编译运行了

1.2 安装gdb并解决没有调式信息的问题

然后如何调式呢?

我们说了Linux中的调式器是gdb,那如何使用gdb调式
如果你的机器上没有gdb可以先安装一下:sudo yum install -y gdb
在这里插入图片描述
然后调式的话,第一步直接gdb+可执行文件名
在这里插入图片描述
然后我们输入相应的指令去调式的话,会发现调不成,有一个报错说的是找不到调试符号

其实就是生成的可执行程序中没有调式信息,怎么回事?又该怎么解决呢?

如果大家平时写C/C++代码用的是vs的话,应该会注意到,在vs上生成程序的时候就有两种模式
在这里插入图片描述

debug和release的了解

两者有什么区别呢?

Debug 通常称为调试版本,它包含调试信息,并且不作任何优化,便于程序员调试程序。
Release 称为发布版本,不包含调式信息,它往往是进行了各种优化,使得程序在代码大小和运行速度上都是最优的,以便用户很好地使用。
所以我们说调试就是在Debug版本的环境中,找代码中潜伏的问题的一个过程。

"Debug"和"Release"是软件开发过程中常见的两种构建(Build)配置。

Debug(调试)配置:

Debug 配置旨在方便开发人员在代码中进行调试和排查错误。
在 Debug 模式下,编译器会生成带有调试符号信息的可执行文件,这些符号信息包含了变量名、函数名和源代码行号等,以便在调试过程中能够准确地追踪错误。
Debug 配置通常会禁用一些优化,以便在调试过程中能够更好地观察程序的行为。
此配置的构建速度较慢,生成的可执行文件较大。

Release(发布)配置:

Release 配置旨在生成用于最终发布的、优化后的代码。
在 Release 模式下,编译器会对代码进行优化,以提高程序的执行效率和性能。
由于优化的存在,生成的可执行文件可能没有调试符号信息,并且可能会合并和删除一些不必要的代码。
Release 配置通常会启用各种优化策略,例如内联函数、循环展开和减少函数调用开销等,以提高代码的执行速度和资源利用率。
此配置的构建速度较快,生成的可执行文件较小。

在实际开发中,通常会使用 Debug 配置进行代码的开发、调试和测试,以便于快速定位和修复问题。而在准备发布软件时,会切换到 Release 配置,以生成性能更高、体积更小的最终可执行文件。

那在Linux上gcc/g++编译生成的可执行程序其实默认是release版本的,不包含调式信息,所以我们无法调式!

如何解决

那如何让它以debug版本生成呢?

很简单
在这里插入图片描述
gcc/g++编译的时候加一个-g就行了

那为了以示区分,我把release版本的重命名一下

在这里插入图片描述

然后我们生成debug版本的,也重命名一下

在这里插入图片描述
那这里我们其实就能看到debug和release版本生成的可执行程序大小的差异。

那我们用gdb调式debug版本的话就不会出现刚才的报错信息了:

在这里插入图片描述

那具体调式要怎么做呢?

接下来我们就来学习一下,gdb中常用的调式操作所涉及的命令

2. gdb的基本使用

2.1 显示代码

那调式的时候,首先我们得能看到代码啊

在这里插入图片描述
打开调式是这样的,那我们想看看代码怎么做?
l(list)+行数:就可以从指定行开始显示代码,一次默认显示10行
在这里插入图片描述
然后后面我们只输l或者直接按回车键(因为gdb会记录你最近一次敲的命令)就可以继续往下显示
在这里插入图片描述
如果第一次只输l的话,随机从某一行开始显示
在这里插入图片描述

2.2 设置、删除和查看断点

那我们调式一般要设断点:

如果你不设断点直接就运行结束了
r(run):开始调式
在这里插入图片描述
不设断点直接调式的话就直接运行完了

那如何设断点呢?

b(break point)+ 行号/函数名:就可以把指定行或指定函数(打在函数内第一条语句处)设置为断点
在这里插入图片描述
如果是多文件的话,我们还可以指定文件去给对应的函数或指定行打断点
b 文件名:行号/函数名
其实查看那里也可以这样来指定
在这里插入图片描述
那设置好我们要查看断点,怎么查看呢?
这可不跟vs上一样,直接有一个红点标记
info b:查看断点
在这里插入图片描述
这里的num是断点的编号,what就是断点的位置,在哪一个文件哪一行。
那有了断点,我们在开始调式的话,当然就会在断点处停下了
在这里插入图片描述

那如何删除一个断点呢?

d(delete)+ 断点编号:删除对应的断点(注意不是行号,而是上面提到的编号)
在这里插入图片描述
直接d就是删除所有断点
在这里插入图片描述
在这里插入图片描述

2.3 禁用和启用断点

对于断点呢还有一个比较冷门的操作,禁用和启用断点:

vs上也有对于对应的操作
在这里插入图片描述
在这里插入图片描述
禁用的话就是不删除这个断点,但让这个断点失效,启用就是让它重新生效。

那在gdb上如何进行对应的操作呢?

大家看这个:
在这里插入图片描述
我们还是把16行设置成断点,然后我们查看的时候,第4列的信息enb(enable breakpoints)如果是y,就表明当前断点是启用状态。
那如果不想删除它,把它设置成禁用,该怎么做呢?
disable breakpoints 断点编号:禁用断点
在这里插入图片描述
然后enb就变成了n,就说明被禁用了
此时如果我们开始调式,它是不会起作用的:
在这里插入图片描述
那如果想启用呢?
enable breakpoints 断点编号:启用断点
在这里插入图片描述

2.4 逐语句和逐过程调式

我们平时用vs调式的时候,常用的其实就是逐语句和逐过程:

在这里插入图片描述
逐过程其实就是一句一句往下执行,遇到函数调用也直接一次就走完了;而逐语句与逐过程的区别就是碰到函数的话会进入到函数体内。

那在gdb中与之对应的操作是什么呢?
首先逐过程:

在这里插入图片描述
开始调式,到16行的断点就停止了,对应的是一个函数调用。
如果我想逐过程,直接走到下一句代码呢?
n/next:逐过程
在这里插入图片描述

那逐语句呢?

我们重新开始调式
在这里插入图片描述
然后又停到了第16行
那我现在想进入函数怎么做?
在这里插入图片描述
s(step):逐语句(遇到函数会进入)

2.5 查看函数调用堆栈

vs上我们调用一些函数的时候可以通过函数调用堆栈查看它们的调用关系:

在这里插入图片描述

那在gdb上如何查看?

breaktrace/bt:查看函数调用堆栈
在这里插入图片描述

2.6 查看指定变量的值

那我们调式不是光一步步执行,重要的是在调式的过程中观察某些变量的值的变化是否和我们预想的一样,从而找出问题。

vs上可以通过监视窗口查看:

在这里插入图片描述

那gdb呢?

p(print)变量名:查看变量的值
在这里插入图片描述
在这里插入图片描述

但是,这样好像有点挫啊,我们敲一次,它显示一次,不敲,下一条语句就不显示了。
那怎么让它一直显示,使得在程序执行的过程中我们可以观察变量的变化呢?

display 变量名:常显示对应变量的值(内置类型和自定义类型均可)
在这里插入图片描述
这样每走一步,我们都能看到变量值的变化。

那现在是常显示,如果执行到某一步我不想让它显示了,怎么取消呢?

undisplay 变量编号:取消对应变量的常显示
注意这里不是跟变量名,而还是它们对应的编号
在这里插入图片描述
在这里插入图片描述

2.7 跳至指定行

现在我们的这个函数的循环还没执行完:
在这里插入图片描述
才执行到i等于8,那现在如果我们单步执行的话他肯定还是一直在这循环,那我想直接让它跳转到循环结束,后面的第10行位置,能做到吗?

是可以的
until 行号:跳至指定行
在这里插入图片描述
此时,程序就直接执行到第10行了。

2.8 只执行完当前函数

再来看一个:

我现在又进入到了这个函数里面
在这里插入图片描述
那我现在想让这个函数直接执行完,然后停下了
那就是finish:执行到当前函数返回,然后停下来等待命令
在这里插入图片描述

2.9 跳转到下一个断点

c(continue):从当前位置执行到下一个断点停下来,后面没有断点则直接到程序结束

我现在设了两个断点
在这里插入图片描述
现在重新开始调式程序
在这里插入图片描述
现在它停在了第一个断点处,我想让它直接跳到下一个断点:
在这里插入图片描述

2.10 修改变量的值

set var 变量名=值:修改变量的值

在这里插入图片描述
然后循环到10就结束了
在这里插入图片描述

2.11 退出gdb

quit:退出gdb

在这里插入图片描述

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/769497.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

STM32学习笔记(十二)丨RTC实时时钟

本篇文章包含的内容 一、计算机底层计时系统——时间戳1.1 时间戳简介1.2 GMT/UTC1.3 C语言和time.h库 二、STM32的BKP和RTC时钟2.1 BKP(Backup Registers)备份寄存器2.2 RTC(Real Time Clock)实时时钟2.2.1 RTC简介2.2.2 RTC的内…

行业追踪,2023-07-18,减速器,汽车零部件是重点关注板块,随时开启

自动复盘 2023-07-18 凡所有相,皆是虚妄。若见诸相非相,即见如来。 k 线图是最好的老师,每天持续发布板块的rps排名,追踪板块,板块来开仓,板块去清仓,丢弃自以为是的想法,板块去留让…

PB从入坑到放弃(五)窗口使用技巧

PB从入坑到放弃(五)窗口使用技巧 一、窗口类型二、窗口属性2.1 General 属性页属性2.2 Scroll 属性页属性2.3 ToolBar 属性页属性2.4 Other 属性页中的属性 三、11种常用控件四、窗口事件4.1 常用事件4.2 举个栗子 五、窗口常用函数5.1 open 函数5.2 clo…

【力扣每日一题】2023.7.19 模拟行走机器人

题目: 示例: 分析: 机器人模拟类题目,力扣里有很多这样的模拟题,就是模拟机器人在坐标系上行走. 套路就是记下每个方向行走后,x轴和y轴的变化(代码中的direction),例如 direction[0] 就表示向北走一次,y轴1,x轴不变.…

防静电门禁闸机的设计和功能

防静电门禁闸机是一种用于控制人员出入的设备,主要用于对人员进行身份验证和进出控制。它的主要功能是防止静电干扰和未经授权的人员进入特定区域。 防静电门禁闸机一般包括以下几个方面的设计和功能: 1. 门禁系统:防静电门禁闸机通常集成了…

宝塔面板登陆不上去了,一直显示加载

宝塔面板登陆不上去了,一直显示加载 半天了登不上去,不知道这是怎么回事? 解答: 您好,服务器内执行bt 16命令先修复,然后重新访问看下。

安卓APK反编译+修改+重打包+签名

目录 1.下载反编译工具包。2.将APK包,重命名为ZIP,解压。放到反编译根目录下。3.使用apktool反编译修改smail文件,进行重打包4.重新打包5.重签名 1.下载反编译工具包。 反编译工具包地址:百度网盘 提取码:dsu3 解压后…

汽配企业专用的MES管理系统与普通系统相比有哪些特征

随着全球化的加速和市场竞争的日益激烈,汽配企业对于生产管理的要求越来越高。为了满足这种需求,越来越多的汽配企业开始引入MES管理系统解决方案来管理和优化其生产线。与传统的普通系统相比,汽配企业MES管理系统具有以下几个显著的特征&…

Ceph 分布式存储之部署

一.Ceph 存储基础 1、单机存储设备 DAS(直接附加存储,是直接接到计算机的主板总线上去的存储) IDE、SATA、SCSI、SAS、USB 接口的磁盘 所谓接口就是一种存储设备驱动下的磁盘设备,提供块级别的存储 NAS(网络附加存储…

谷歌和加州大学伯克利分校的“改革者”在单个GPU上运行64K序列

转换器模型是自然语言处理(NLP)研究领域越来越流行的神经网络架构,大型变压器可以在许多任务上实现最先进的性能。代价是转换器过多的计算消耗和成本,尤其是对于长序列上的训练模型。 谷歌和加州大学伯克利分校的研究人员最近发表…

C#被指定窗体的MdiParent的窗体不是MdiContainer

工作的时候遇到一个问题: 被指定窗体的MdiParent的窗体不是MdiContainer 这个问题的原因是父窗体的IsMdiContainer 属性设置为false导致的。将此属性设置为true,即可解决此问题。有两种方式设置窗体的IsMdiContainer 属性。 第一种,在父窗口…

IndexedDB

IndexedDB 操作流程打开数据库新建数据库新增数据读取数据遍历数据更新数据删除数据使用索引案例 indexedDB对象indexedDB.open() 操作流程 打开数据库 使用IndexedDB 的第一步是打开数据库,使用indexedDB.open()方法 // 第一个参数是字符串,表示数据…

MyBatis注解开发

1 Mybatis注解开发单表操作 1.1 MyBatis的常用注解 Mybatis也可以使用注解开发方式,这样可以减少编写Mapper映射文件 Insert:实现新增 Update:实现更新 Delete:实现删除 Select:实现查询 Result:实现…

【MongoDB实战】数据备份与恢复(部分迁移)

场景: 需求: 解决方案: 步骤: Stage 1:【生产环境】修改备份文件映射 Stage 2:【生产环境】重新构建mongodb Stage 3:【客户环境】修改备份文件映射,同 Stage 1 Stage 4&…

FPGA+x86构建高性能国产网络测试仪竞技之道

众所周知,以太网已经深入我们的生活无处不在,企业、校园、大数据中心和家庭等都离不开网络,否则我们的生活将受到严重的影响。 以太网的接口速率也是迅速发展:10M、100M、GE、10GE、40GE、100GE,到目前逐步成熟的2.5G…

数据结构与算法——静态链表及其创建(C语言实现)

《顺序表和链表优缺点》里面,我们了解了两种存储结构各自的特点,那么,是否存在一种存储结构,可以融合顺序表和链表各自的优点,从而既能快速访问元素,又能快速增加或删除数据元素。 静态链表,也…

【雕爷学编程】Arduino动手做(22)——8X8 LED点阵MAX7219屏7

37款传感器与模块的提法,在网络上广泛流传,其实Arduino能够兼容的传感器模块肯定是不止37种的。鉴于本人手头积累了一些传感器和模块,依照实践出真知(一定要动手做)的理念,以学习和交流为目的,这…

Java开发中使用sql简化开发

引语: 在Java开发中,我们更希望数据库能直接给我们必要的数据,然后在业务层面直接进行使用,所以写一个简单的sql语句有助于提高Java开发效率,本文由简单到复杂的小白吸收,还请多多指教。 使用MySQL数据库…

GO 语言GC

目录 写屏障 读屏障 GO语言GC准备 堆内存结构: GC内存分配: GC触发: P的作用: 写屏障 实现强弱三色不式,为了避免误删,则实现写屏障. 写屏障是在写操作中插入指令,目的是把数据对象的修改通知到GC GO语言支持两种写屏障 读屏障 非移动垃圾回收(例如 三色)天…

详解c++---智能指针

目录标题 为什么会有智能指针智能指针模拟实现库中的智能指针auto_ptrunique_ptrshared_ptr 智能指针的线程安全问题循环智能指针weak_ptr定制删除器定制删除器的实现 为什么会有智能指针 根据前面的知识我们知道使用异常可能会导致部分资源没有被正常释放,因为异常…