【C语言基础】gdb调试工具的使用

gdb调试教程

快速入门

要想快速入门gdb调试,可以直接翻阅基本案例:采内存

介绍

GDB是一个由GNU开源组织发布的、UNIX/LINUX操作系统下的、基于命令行的、功能强大的程序调试工具。 对于一名Linux下工作的c/c++程序员,gdb是必不可少的工具

常用指令

  • shell 指令
指令用法介绍
gdbgdb +${exe}对生成的可执行文件进行调试
gdb -qgdb -q +${exe}对生成的可执行文件进行调试
表示不打印gdb版本信息,界面较为干净;
  • gdb指令
指令用法介绍
断点设置
breakbreak +Line<br>break+{Line}<br>break +Line<br>break+{func}可以对行号和函数进行设置断点
程序运行
runrun / r首次运行程序,运行到第一个断点
continuecontinue / c继续运行程序,运行到下一个断点
nextnext / n单步跳过,(执行一步程序,遇到函数,直接完成函数操作,不会进入函数)
stepstep / s单步进入,(执行一步程序,遇到函数会进入)
untiluntil / u + ${Line}跳出循环体,并跳到循环体外部的某一行
变量查看
printprint +变量打印变量的值
whatiswhatis +变量打印变量的类型
quitquit / q退出
可视化
layout src调试的时候同时显示源代码窗口,但是必须run之后才会显示

基本案例:采内存

0. 源码

本案例以下文段错误(采内存)源码进行介绍如何进行gdb调试。

通常在复杂程序调用中,指针的操作容易导致编程人员对内存空间的使用造成困扰和混乱,因此指针操作是导致内存异常问题最为常见的因素也是最难定位的因素。

源代码如下:

在本案例中,main函数里的my_user指针在addUser函数里进行资源申请。虽然成功申请到了堆中的空间。但是因为my_user是作为参数传入,因此在函数返回时,my_user又重新指向了NULL,而非堆上的空间地址导致运行发生段错误。

#include <stdio.h>
#include <stdlib.h>typedef struct User {int id;int age;
} User;void addUser(User *user, int id, int age)
{user = (User *)malloc(sizeof(User));user->id = id;user->age = age;printf("id = %d, age = %d\n", user->id, user->age);
}int main()
{printf("gdb demo\n");User *my_user = NULL;addUser(my_user, 10, 20);printf("id = %d, age = %d\n", my_user->id, my_user->age);return 0;
}

1. 编译

要想使用gdb调试功能,需要在gcc编译器添加-g参数,或者在cmake里编译成debug模式。

>> gcc -g -o main main.c

2. 打开gdb调试

>> gdb main 
>> gdb -q main # 表示不打印gdb版本信息,界面较为干净;

3. gdb 设置断点

  • break
  • info breakpoints
# 使用 break 或者 b 进行设置断点。
# 可以对函数进行打点,或者对代码行进行打点。
# 我们可以使用info breakpoints查看当前所有的断点信息
(gdb) b addUser 
Breakpoint 1 at 0x752: file gdb_test.c, line 11.
(gdb) b 13
Breakpoint 2 at 0x769: file gdb_test.c, line 13.
(gdb) b 20
Breakpoint 3 at 0x7aa: file gdb_test.c, line 20.
(gdb) info breakpoints 
Num     Type           Disp Enb Address            What
1       breakpoint     keep y   0x0000000000000752 in addUser at gdb_test.c:11
2       breakpoint     keep y   0x0000000000000769 in addUser at gdb_test.c:13
3       breakpoint     keep y   0x00000000000007aa in main at gdb_test.c:20 

4. 运行

  • run
  • continue
  • next
  • step
# 当我们设置完断点进行调试的时候,首先要执行run函数开启程序进程,run会执行到第一个断点位置
# 然后我们可以执行next 或者 continue 或者 step进行推进程序
# continue: 运行到下一个断点
# next: 单步跳过,(执行一步程序,遇到函数,直接完成函数操作,不会进入函数)
# step: 单步进入,(执行一步程序,遇到函数会进入)
(gdb) run
Starting program: /home/rodney/ProjectCode/Cproject/C_coding/gcc&g++&gdb_block/bug1/main 
gdb demoBreakpoint 3, main () at gdb_test.c:20
20		User *my_user = NULL;
(gdb) n
22		addUser(my_user, 10, 20);
(gdb) c
Continuing.Breakpoint 1, addUser (user=0x0, id=10, age=20) at gdb_test.c:11
11		user = (User *)malloc(sizeof(User));(gdb) c
Continuing.Breakpoint 2, addUser (user=0x555555756420, id=10, age=20) at gdb_test.c:13
13		user->age = age;(gdb) n
14		printf("id = %d, age = %d\n", user->id, user->age);
(gdb) n
id = 10, age = 20
15	}
(gdb) n
main () at gdb_test.c:23
23		printf("id = %d, age = %d\n", my_user->id, my_user->age);
(gdb) nProgram received signal SIGSEGV, Segmentation fault.
0x00005555555547cc in main () at gdb_test.c:23
23		printf("id = %d, age = %d\n", my_user->id, my_user->age);

从上文可以看出是23行打印发生了报错,那么如何确定23行的打印发生了什么具体错误,可以使用printwhatis进行打印显示。

5. 打印和显示变量信息

  • print 打印变量的值
  • whatis 打印变量的类型
# 从打印的信息可以看出,这里my_user是个空指针,因此访问出现上文的段错误。
(gdb) whatis my_user
type = User *
(gdb) whatis my_user->id
type = int
(gdb) print my_user
$1 = (User *) 0x0
(gdb) print my_user->id
Cannot access memory at address 0x0

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

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

相关文章

C/C++队列与循环队列

C/C数据结构 - 队列 循环队列 快速入门 介绍 1. 队列的定义 队列是一种线性存储结构&#xff0c;每次对队列的增删操作如下 增&#xff1a;在队列尾部添加元素 删&#xff08;取出&#xff09;&#xff1a;在队列头部删除元素 这种数据存储方式遵循“先进先出”&#xff0…

PyQt特殊对话框介绍

PyQt特殊对话框 对话框基类&#xff1a;QDialog 对话框基本用法&#xff1a; 模态窗口&#xff1a; 当窗口设置为模态窗口时&#xff0c;不能对其父级别的窗口进行操作。QTdesigner里有控件可以勾选Func: QtWidgets.Dialog.setModal(True) [ True | False ] 窗口执行 exec&am…

PyQt5 让窗口在桌面居中的办法

屏幕居中核心函数 在我们开发的UI类中定义一个center方法&#xff0c;&#xff08;方法名自定&#xff0c;内容如下&#xff09;。其中QDesktopWideget方法在Qtwidgets头文件中。 然后在 __init__()中调用该 self.center()方法即可。 # 屏幕居中def center(self):# 获取窗口大…

PyQt5 QLineEdit输入密码

单行编辑器 QLineEdit 输入密码 单行编辑器直接继承于QWidget 常用方法&#xff1a; 设置显示模式&#xff1a;在设置密码栏常会使用这种模式 方法QLineEdit.setEchoMode 用法 假设你有一个QLineEdit()组件 self.UserpswdEdit QLineEdit()则你可以使用下面三种方式定义输…

Arduino 软件开发(一): GPIO读写

Arduino 软件开发&#xff08;一&#xff09; 目录 核心运行函数&#xff0c; 基础语法&#xff0c;数字控制&#xff0c;模拟控制 核心运行函数 void setup() 当Arduino程序开始运行时会调用setup()函数。通常setup()函数完成初始化一些变量、配置引脚状态及初始化调用的库…

JavaScript学习笔记:类与导包实例

NodeJS类与导包 在工程上&#xff0c;一个文件就是一个独立的模块&#xff0c;仅包含一个类。我们可以称之为类文件。因此当我们要使用这个模块的时候&#xff0c;我们会将这个类文件作为一个包导入到调用的文件里。方法如下&#xff1a; 0. 目录结构如下 - src|__ main.js|…

JavaScript学习笔记:常量,枚举,宏定义

NodeJS常量&#xff08;fake&#xff1a;宏定义&#xff09; 因为之前C/C代码开发习惯了&#xff0c;会用到一些宏定义来替换一些表意不明的数字&#xff08;就是含义不清的数字&#xff09;。而JS没有这种宏定义。上网找到一个链接作为参考&#xff1a;https://www.itranslat…

JavaScript学习笔记:函数与箭头函数

NodeJS函数 由于js是弱语言&#xff0c;因此&#xff0c;函数的入参和出参可以为任意形式而不用指定类型。当然也没有办法使用冒号的形式进行参数类型注释。但是typescript可以使用冒号形式进行参数类型注释。 1. 普通的函数定义 不带参数形式printHello带参数形式plus使用re…

Python学习笔记(1):用户输入,终端输入

#用户输入&#xff0c;操作 print("python 用户输入操作")# input(提示字符串)&#xff0c;函数阻塞程序&#xff0c;并提醒用户输入字符串 instr input("please input the string: ") print("input >> " instr)# 将输入的字符串转化成整…

Python学习笔记(2):生成器

介绍 我们可以通过列表生成式简单直接地创建一个列表&#xff0c;但是受到内存限制&#xff0c;列表容量肯定是有限的。而且&#xff0c;创建一个包含100万个元素的列表&#xff0c;不仅占用很大的存储空间&#xff0c;而且如果我们仅仅需要访问前面几个元素&#xff0c;那后面…

Python学习笔记(3):zipfile解压库

简介 python自带zipfile解压库&#xff0c;导入方式如下 import zipfile批量解压 先尝试无密码解压&#xff0c;如果失败&#xff0c;就输入密码。但是zipfile解压大文件速度很慢。 path rL:/resource/zipPackage passwd b123456 def compressFromZip():for temp_name in…

数字万用表使用方法

数字万用表使用方法 简介&#xff1a;数字万用表相对来说&#xff0c;属于比较简单的测量仪器。本篇&#xff0c;作者就教大家数字万用表的正确使用方法。从数字万用表的电压、电阻、电流、二极管、三极管、MOS场效应管的测量等测量方法开始&#xff0c;让你更好的掌握万用表测…

Python学习笔记(4):Python如何设置类似C语言静态函数

介绍 模块封装时候&#xff0c;希望有一些函数不被外部直接调用。C语言通常采用static int function()形式以及头文件形式作为标识。而python不存在头文件&#xff0c;但可以通过修饰符staticmethod进行代替。 staticmethod def your_function():# 你的代码print("your …

c++ 字符串相等比较

介绍 在C 中比较字符串的技术 (Techniques to Compare Strings in C) Strings in C can be compared using either of the following techniques: 可以使用以下两种技术之一来比较C 中的字符串&#xff1a; String strcmp() function 字符串strcmp&#xff08;&#xff09;函…

ffmpeg下载安装 多段ts视频m3u8下载

如何下载多段ts视频 m3u8 ffmpeg ffmpeg使用教程 下载 Windows下载方法 step1. 官网下载地址 点此进入下载地址 step2. 选择 Windows EXE files 中的Windows builds by BtbN 这会跳转到github页面中。 step3. 选择对应的linux平台或者windows平台进行下载 安装 step1.…

linux环境下安装多个任意版本的python环境

linux环境下安装多个任意版本的python环境 安装方法可以归结为 [下载 编译 配置环境变量] 下载Python 参考链接&#xff1a; .任意python版本下载&#xff0c;所有python版本下载的FTP路径 Windows下载发送到linux上 step1. 下载linux版本的python 从Python官网进入 选择…

linux云服务器状态上报解决方案:外发个人邮箱

linux云服务器状态上报解决方案&#xff1a;外发个人邮箱 需求如下&#xff1a; #### 将一些服务器的关键日志实时发送到手机上一些案例&#xff1a; CPU状态检测 解决方案&#xff1a; #### 利用mailx命令外发邮件方法如下&#xff1a; 1. 用管理员打开mail配置文件 >…

Matplotlib画图教程:在QT界面中嵌入三维图片

Matplotlib画图教程&#xff1a;在QT界面中嵌入三维图片 需求&#xff1a; 做项目报告的时候&#xff0c;有这么一个想法&#xff0c;就是能通过UI随时调用matplotlib进行二维图和三维图的绘制。因此就诞生了做这么一个小模块的想法。 这里先上一下最终结果&#xff1a; 思…

Python工程笔记(1):轨迹与日志

轨迹记录模块&#xff08;Recorder&#xff09; 轨迹和日志是定位工程问题的备忘录和总结代码开发项目管理经验的基本素材&#xff0c;是工程交验收资料的重要组成部分 1.1 依赖表 包名含义安装方式系统包ostime 1.2 全局变量表 变量名含义初值log_file日志保存路径./recor…

Python代码优化(1):天气预报获取

天气预报获取模块 基于http://www.weather.com.cn/做了代码优化&#xff0c;每个函数功能更加明确&#xff0c;更加适合单独集成。接口也进行了优化&#xff0c;比网络上博主抄来抄去的源码要好一些。 改进点&#xff1a;获取天气拆成了多个函数&#xff0c;多次保存csv文件不…