?一、 Linux调试器 - gdb✨1. gdb是什么
gdb 是 gnu 项目开发的一个命令行源代码级调试器。它是 #%#$#%@%@%$#%$#%#%#$%@_e206a54e97690c++e50cc872dd70ee896 和其他类 unix 系统(如 macos,bsd)上 c、c++、rust、go、fortran 等编程语言开发的标准调试工具。简单来说,gdb 允许你深入正在运行的程序内部:
1️⃣启动程序: 在受控环境下运行你的程序。2️⃣暂停执行: 在特定点(断点)或发生特定事件(如信号)时停止程序。3️⃣检查状态: 当程序暂停时,你可以查看: 变量的值(局部变量、全局变量)。 程序执行到了哪一行源代码。 函数调用堆栈(backtrace)。 寄存器的内容。 内存区域的内容。4️⃣控制执行: 在暂停点之后,你可以: 单步执行代码(逐行 step 或逐过程 next)。 继续执行直到下一个断点或程序结束 continue。 跳入函数调用 step 或跳过函数调用 next。 跳出当前函数 finish。 甚至在运行时修改变量的值(小心使用!)。5️⃣分析崩溃: 当程序崩溃(如段错误 Segmentation Fault)时,GDB 可以加载产生的 core dump 文件,让你查看程序崩溃时的状态(调用栈、变量值等),极大地方便了事后分析。总结的说就是和VS环境中进行调试是一样的效果,只不过操作不同罢了
✨2. gdb的使用更改发行版本:默认情况下我们在Linux上是无法进行调试的,因为gcc/g++默认生成的可执行是release版本的
那么如何更改Linux下的发行版本?
gcc test.c -o testdebug -g
只需在gcc编译时后面加入-g即可

使用指令
readelf -S XXXX(可执行文件名称)
就可以查看Linux下可执行程序二进制代码的一些信息。elf就是Linux下的可执行文件格式形式,可以观察到,debug版本里面多了一些调试信息

我们将以下述代码为例进行调试:
代码语言:javascript代码运行次数:0运行复制1 #include1️⃣进入调试模式使用指令gdb XXX(调试版本可执行)2 3 4 int Add(int left, int right) 5 { 6 return left + right; 7 } 8 9 int main() 10 { 11 int sum = Add(10, 20); 12 printf("sum = %d\n", sum); 13 printf("hello gdba\n"); 14 printf("hello gdbb\n"); 15 printf("hello gdbc\n"); 16 printf("hello gdbd\n"); 17 printf("hello gdbe\n"); 18 printf("hello gdbf\n"); 19 printf("hello gdbg\n"); 20 printf("hello gdbh\n"); 21 printf("hello gdbi\n"); 22 printf("hello gdbj\n"); 23 return 0; 24 }













总结:
上面的指令都了解的话,用起来gdb已经没啥大问题了,下面把常见的一些gdb指令总结一下,如果再后续的使用过程中用到了,大家回来查阅即可。
先看一段代码:
代码语言:javascript代码运行次数:0运行复制#include#include int main(){ printf("这是一个试验程序"); sleep(3); return 0;}
运行之后,会发现,printf竟然没有打印,而是停了3秒之后才出现,相信你会说,你自己sleep了3秒,能怪人家不出现?请看下述代码:
代码语言:javascript代码运行次数:0运行复制printf("这是一个试验程序\n"); 如果在printf加了回车换行,你会惊奇的发现,printf先打印,然后休眠了3秒之后代码才结束,这是为何?好,知识点来了。
知识点1:
首先针对于没有回车换行,为什么没有?
是因为此时printf所要打印的内容,储存在了缓冲区,而有了\n为什么就有了呢?
这涉及到了标准输出(stdout)的缓冲机制,如下:
缓冲机制类型
行缓冲(Line-buffered):遇到换行符\n 时自动刷新缓冲区(立即输出内容)。 全缓冲(Fully-buffered):缓冲区满或显式刷新时才输出。 无缓冲(Unbuffered):立即输出(如 stderr)。 而终端环境下的 stdout 默认是行缓冲
因此两段代码的具体解释如下:
代码语言:javascript代码运行次数:0运行复制printf("这是一个试验程序\n"); // 末尾有换行符sleep(3); \n 触发刷新:换行符使缓冲区立即刷新,内容立刻显示在终端。 后续休眠:之后程序休眠 3 秒,用户先看到输出,再等待。 代码语言:javascript代码运行次数:0运行复制printf("这是一个试验程序"); // 无换行符sleep(3); 缓冲区未刷新:输出内容暂存于内存缓冲区(未满且未遇到 \n)。 先休眠 3 秒:程序进入休眠,此时终端无输出。 程序结束时刷新:main 函数返回前,自动刷新所有缓冲区,内容在休眠结束后显示。 所以也就是说终端环境下stdout是行缓冲,\n有刷新行缓冲区的功效,是!怎么证明?如下:
代码语言:javascript代码运行次数:0运行复制int main(){ printf("这是一个试验程序"); fflush(stdout); sleep(3); return 0; } fflush是刷新缓冲区的,此时你便会看到,先打印结果,再休眠3秒,关于缓冲区的具体知识,在我们学习到Linux后面的时候就会明白

对于上述回车换行,我们见下一段代码:
代码语言:javascript代码运行次数:0运行复制int main(){ int cnt = 10; while(cnt) { printf("这是一个倒计时:%2d\r", cnt); fflush(stdout); cnt--; sleep(1); } return 0;}/r就是回车的作用,但是它没有刷新缓冲区的功能,所以我们每次要进行刷新缓冲区才能看到一个正常的倒计时,如下:

有了前面的知识铺垫,我们就可以写一个Linux下第一条小程序进度条如下所示:

首先,需要101个字符数组,因为最后一个需要放‘\0’,因而需要101个空间
代码语言:javascript代码运行次数:0运行复制#define NUM 101char pg[NUM];memset(pg, '\0', sizeof(pg));
其次需要对这个数组进行初始化,并且数组赋值肯定是在一个循环当中的,因此需要定义一个临时变量,一来控制循环,二来改变数组里面的值。对于%后面的小圈圈,我们可以让| \ - / 四个字符轮流转换视觉上就显示的是转圈圈。
代码语言:javascript代码运行次数:0运行复制char cir[4] = {'|', '\\', '-', '/'};int cnt = 0; while(cnt <= 100) { printf("[%-100s][%d%%][%c]\r", pg, cnt, cir[cnt % 4]); fflush(stdout); pg[cnt++] = STYLE; usleep(50000); }对于fflush,与sleep上面例子有不再赘述,至于usleep是为了让它走得相对快些,让它5秒走完,粗略为100次循环,则每次是5/100 = 0.05,usleep是微秒,则0.05*1000000 = 50000,所以让它休眠50000微秒
本篇博客我们主要了解了 Linux 调试器 gdb 和 Linux 下的进度条程序。gdb 是一个命令行源代码级调试器,可用于调试多种编程语言,在 Linux 等系统中发挥重要作用,通过示例代码展示了其基本使用方法,如设置断点、查看变量等。同时,讲解了 Linux 下第一条程序 —— 进度条的实现,介绍了 printf 的缓冲机制以及如何利用相关函数实现动态进度条效果。希望大家有所收获!










