前言: 本篇博客我们来了解最后一个工具gdb,至此我们在Linux上就可以进行编写代码、调试代码、编译代码,一整套完整的线路便贯穿了起来,文章结尾我们就开始在Linux上写第一段程序进度条以此打开Linux新篇章。如果大家对于之前工具陌生或者遗忘那个,请务必进行复习,不然难以进行,大家加油!
GDB 是 GNU 项目开发的一个命令行源代码级调试器。它是 Linux 和其他类 Unix 系统(如 macOS,BSD)上 C、C++、Rust、Go、Fortran 等编程语言开发的标准调试工具。简单来说,GDB 允许你深入正在运行的程序内部:
backtrace
)。step
或逐过程 next
)。continue
。step
或跳过函数调用 next
。finish
。core dump
文件,让你查看程序崩溃时的状态(调用栈、变量值等),极大地方便了事后分析。总结的说就是和VS环境中进行调试是一样的效果,只不过操作不同罢了
默认情况下我们在Linux上是无法进行调试的,因为gcc/g++默认生成的可执行是release版本的
相信在学习C语言时所使用的VS环境,页面上方有release/debug更换的按钮,那么到底是什么意思呢? debug版本就是生成的可执行是调试版本,里面加了一些供程序员进行调试的信息 release版本就是去掉了调试的信息,文件大小更小了,把一些对于用户没有价值的东西去掉 总结如下: 特性Debug 版本Release 版本优化等级无优化(
-O0
)高级优化(如-O2
/-O3
)调试符号包含(可被 GDB 等调试器读取)不包含(或剥离)代码可读性代码顺序与源代码一致代码被重排、内联、删减(难以阅读)性能慢(保留所有检查)快(激进优化)文件大小大(含调试信息)小(无冗余信息)运行时检查启用(如断言assert()
)禁用(断言被忽略)适用场景开发、调试阶段正式部署给用户
那么如何更改Linux下的发行版本?
gcc test.c -o testdebug -g
只需在gcc编译时后面加入-g即可
使用指令
readelf -S XXXX(可执行文件名称)
就可以查看Linux下可执行程序二进制代码的一些信息。elf就是Linux下的可执行文件格式形式,可以观察到,debug版本里面多了一些调试信息
我们将以下述代码为例进行调试:
1 #include<stdio.h>
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已经没啥大问题了,下面把常见的一些gdb指令总结一下,如果再后续的使用过程中用到了,大家回来查阅即可。
先看一段代码:
#include<stdio.h>
#include<unistd.h>
int main()
{
printf("这是一个试验程序");
sleep(3);
return 0;
}
运行之后,会发现,printf竟然没有打印,而是停了3秒之后才出现,相信你会说,你自己sleep了3秒,能怪人家不出现?请看下述代码:
printf("这是一个试验程序\n");
如果在printf加了回车换行,你会惊奇的发现,printf先打印,然后休眠了3秒之后代码才结束,这是为何?好,知识点来了。
知识点1:
首先针对于没有回车换行,为什么没有?
是因为此时printf所要打印的内容,储存在了缓冲区,而有了\n为什么就有了呢?
这涉及到了标准输出(stdout)的缓冲机制,如下:
缓冲机制类型
\n
时自动刷新缓冲区(立即输出内容)。
stderr
)。
而终端环境下的 stdout
默认是行缓冲
因此两段代码的具体解释如下:
printf("这是一个试验程序\n"); // 末尾有换行符
sleep(3);
\n
触发刷新:换行符使缓冲区立即刷新,内容立刻显示在终端。
printf("这是一个试验程序"); // 无换行符
sleep(3);
\n
)。
main
函数返回前,自动刷新所有缓冲区,内容在休眠结束后显示。
所以也就是说终端环境下stdout是行缓冲,\n有刷新行缓冲区的功效,是!怎么证明?如下:
int main()
{
printf("这是一个试验程序");
fflush(stdout);
sleep(3);
return 0;
}
fflush是刷新缓冲区的,此时你便会看到,先打印结果,再休眠3秒,关于缓冲区的具体知识,在我们学习到Linux后面的时候就会明白
知识点2: 上面提到了回车换行,怎么那么陌生,我们不都常说换行嘛,怎么来个回车换行,什么意思? 换行是换行,回车是回车,换行的意思是换到下一行但是不回退到下一行的初始位置 回车是在当前行回退到初始位置 回车换行就是既换到下一行又回退到下一行的初始位置,即我们键盘的ENTER键
对于上述回车换行,我们见下一段代码:
int main()
{
int cnt = 10;
while(cnt)
{
printf("这是一个倒计时:%2d\r", cnt);
fflush(stdout);
cnt--;
sleep(1);
}
return 0;
}
/r就是回车的作用,但是它没有刷新缓冲区的功能,所以我们每次要进行刷新缓冲区才能看到一个正常的倒计时,如下:
有了前面的知识铺垫,我们就可以写一个Linux下第一条小程序进度条如下所示:
首先,需要101个字符数组,因为最后一个需要放‘\0’,因而需要101个空间
#define NUM 101
char pg[NUM];
memset(pg, '\0', sizeof(pg));
其次需要对这个数组进行初始化,并且数组赋值肯定是在一个循环当中的,因此需要定义一个临时变量,一来控制循环,二来改变数组里面的值。对于%后面的小圈圈,我们可以让| \ - / 四个字符轮流转换视觉上就显示的是转圈圈。
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微秒
尤其注意: [%-100s][%d%%][%c]\r,\r必须要放置在最后,不然就会让一部分括号跑到前面,因为回车你把前面的东西清零,\r后面的东西就会跟着上前,每次都是这样,时间如果短的话就会视觉上显示\r后面的东西在前面。 %100s是预留100个空间,没有-是右对齐 %-100s是预留100个空间,并且是左对齐 %是一个特使符号如果要显示%必须%% cnt % 4:是为了让每次数值控制在0-3以此让小圈圈转起来
本篇博客我们主要了解了 Linux 调试器 gdb 和 Linux 下的进度条程序。gdb 是一个命令行源代码级调试器,可用于调试多种编程语言,在 Linux 等系统中发挥重要作用,通过示例代码展示了其基本使用方法,如设置断点、查看变量等。同时,讲解了 Linux 下第一条程序 —— 进度条的实现,介绍了 printf 的缓冲机制以及如何利用相关函数实现动态进度条效果。希望大家有所收获!