【Linux】想学习Linux不看这一篇你就慢了-->工具篇(四)gdb、进度条程序
更新时间:2026-02-23 13:16:08
-
-
爱情和生活模拟rpg手机版
- 类型:体育竞技
- 大小:87.5mb
- 语言:简体中文
- 评分:
- 查看详情
【Linux】想学习Linux不看这一篇你就慢了-->工具篇(四)gdb、进度条程序
?一、 Linux调试器 - gdb1. gdb是什么
gdb是gnu项目开发中不可或缺的调试工具在现代编程中,断点调试器扮演着至关重要的角色。它是一个命令行下的源代码级调试器,适合多种类Unix系统(如macOS、BSD)上进行C、C++、Rust、Go和Fortran等语言的开发。简单来说,gdb允许你深入到正在运行的程序内部,实现以下功能: 启动程序:在受控环境下运行你的程序。 暂停执行:在特定点(断点)或发生特定事件时停止程序。 检查状态:当你暂停时,可以查看变量值(局部、全局)、程序行源代码位置、函数调用堆栈、寄存器内容以及内存区域的内容等信息。 控制执行: - 单步执行代码(逐行step或逐过程next)。 - 继续执行直到下一个断点或程序结束(continue)。 - 跳入函数调用(step或finish)。 - 跳过函数调用(next)。 - 在运行时修改变量的值(注意:小心使用)。 分析崩溃:当程序崩溃时,GDB可以加载产生的core dump文件,让你查看程序崩溃时的状态(调用栈、变量值等),极大地方便了事后分析。总之,gdb是一个强大的工具,它能帮助你深入理解代码的运行过程,解决复杂问题,并提高编程效率。
总结为在GDB中更换发行版与使用VS环境调试的效果相同,只是操作方式有所不同。
默认情况下我们在Linux上是无法进行调试的,因为gcc/g++默认生成的可执行是release版本的
那么如何更改Linux下的发行版本?
gcc test.c -o testdebug -g
只需在gcc编译时后面加入-g即可

使用指令
readelf -S XXXX(可执行文件名称)
在Linux系统中,可以通过el文件(Executable and Linkable Format的缩写)来查看可执行程序的二进制代码及附加的信息。例如,Debug版本包含了更多的调试信息,这有助于开发和维护程序时的错误诊断。
调试阶段:

我们将以下述代码为例进行调试:代码语言:javascript代码运行次数:0
运行
复制
- #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 ", sum); 13 printf("hello gdba "); 14 printf("hello gdbb "); 15 printf("hello gdbc "); 16 printf("hello gdbd "); 17 printf("hello gdbe "); 18 printf("hello gdbf "); 19 printf("hello gdbg "); 20 printf("hello gdbh "); 21 printf("hello gdbi "); 22 printf("hello gdbj "); 23 return 0; 24 }登录后复制1进入调试模式使用指令gdb XXX(调试版本可执行)
- 示代码指令:l l + n(行号):从第n行开始显示

断点相关指令: - 使用 `break` 和 `行号` 设置断点,指示在某一行停止执行。 - 使用 `b 函数名` 在函数开头设置断点;使用 `info break` 查看当前断点信息。 - 若要删除一个断点,只需输入其编号并按回车键。

在r中,按“Run”键启动程序。若有断点,将在第一个断点后暂停;若无断点,则程序将自动执行直至下一次断点。

n:逐过程,即在调用函数处不进入函数内部s:逐语句,在调用函数处进入函数内
显示变量 `breaktrace`(或 `bt`):查看各级函数调用堆栈。 变量: 打印变量值。该指令仅会显示一次,不会随着程序的执行而变动。 display 变量: 常显示变量,类似VS环境中随着程序的变动而改变。 这个命令会让你能够实时观察和追踪变量的状态变化。 undisplay 变量编号: 将常显示变量取消,恢复正常显示方式。

完成指令:在达到当前函数后返回并停止等待命令。此指令允许我们分析错误发生在哪个函数中。等待指令:跳转到特定行,然后已经执行的前半部分程序继续运行。这两个指令帮助我们在代码中追踪问题和调试过程中的步骤。
- 出调试模式指令 quit:退出gdb。q即可

总结:
上面的指令都理解了,接下来我将总结一些常见的gdb(GNU Debugger)指令。这些信息可以在需要时查阅以优化调试体验。列表(List) - `list /l 行号`:显示从当前行号开始的源代码,每次列。 - `list /l 函数名`:列出指定函数的源代码。运行程序(Run) - `run` 或 `r`:运行程序。 - 模拟单条执行(Next): `n` 或 `next`。 - 进入函数调用断点(Step): `s` 或 `step`。设置和删除断点(Breakpoint) - 设置断点:`break 行号`或`break 函数名`。 - 删除所有断点:`delete breakpoints`。 - 删除序号为n的断点:`delete breakpoints n`。 - 禁用断点:`disable breakpoints`。 - 启用断点:`enable breakpoints`。查看和修改变量(Set) - 修改变量值:`set var = value`。 - 打印变量的值或调用函数:`print p 变量名` 或 `p 变量名`。继续执行程序(Continue) - 连续非单步执行程序:`continue` 或 `c`。 - 跳至行号:`until X 行号`。
运行
复制
#include<stdio.h>#include<unistd.h>int main(){ printf("这是一个试验程序"); sleep(3); return 0;}登录后复制
当程序执行过程中,print函数实际只是将输出内容存储在缓冲区中,并没有立即显示出来。为了触发此行为,在控制台使用window.print替代print,你会发现输出不会立即显现,而是稍后自动更新。这通常用于需要即时打印而不干扰其他操作的情况。
运行
复制
printf("这是一个试验程序 "); 登录后复制
当你使用`printf`函数并添加回车换行符时,程序会先输出内容,然后暂停钟再继续执行其他代码。这是因为编译器和运行环境需要时间来处理和显示这些信息,同时确保后续操作有足够的时间进行。
知识点1:
首先针对于没有回车换行,为什么没有?
是因为此时printf所要打印的内容,储存在了缓冲区,而有了 为什么就有了呢?
这涉及到了标准输出(stdout)的缓冲机制,如下:
缓冲机制类型 行缓冲(Line-buffered):遇到换行符时自动刷新缓冲区并即时输出内容。 全缓冲(Fully-buffered):当缓冲区满或显式刷新时才输出数据。 无缓冲(Unbuffered):立即输出,如标准错误流。
而终端环境下的 stdout 默认是行缓冲
因此两段代码的具体解释如下:代码语言:javascript代码运行次数:0
运行
复制
```javascript console.log(这是一个试验程序); // 结尾带有换行符 window.setTimeout( => { window.location.reload; }, ; // 触发刷新:利用换行符立即刷新缓冲区,内容立刻显示在终端。后续休眠:程序等待后再次运行。 ```
运行
复制
```cpp printf(这是一个试验程序\n); // 在此代码中,添加了换行符以确保输出有格式 // sleep(; login; while(!flushed); // 登录后复制这段代码中的注释 while (memoryBufferNotEmpty) { // 缓冲区未刷新的描述被更改为缓冲区状态检测 wait; // 当达到内存缓冲区未满且未遇到异常情况时,程序进入休眠阶段 } resetConsole; // 程序结束时刷新所有缓冲区,确保内容在休眠结束后显示 ```
所以,在终端环境下,`stdout` 是通过行缓冲来实现刷新效果的。这种机制确保了输出信息逐行显示,提供了一种良好的交互体验。以下是对这一现象的说明和验证示例: JavaScript代码```javascript // 证明 `stdout` 的行缓冲功能 console.log(这是一个示例); console.log(这是另一个示例);setTimeout( => { console.log(这个是第三段内容); }, ; ```这段代码通过控制台输出三段内容,每一行的显示之间有短暂的时间间隔。这说明了 `stdout` 的刷新功能在实际应用中的表现。
运行
复制
int main(){ printf("这是一个试验程序"); fflush(stdout); sleep(3); return 0; } 登录后复制
fflush是刷新缓冲区的,此时你便会看到,先打印结果,再休眠3秒,关于缓冲区的具体知识,在我们学习到Linux后面的时候就会明白

对于上述回车换行,我们见下一段代码:代码语言:javascript代码运行次数:0
运行
复制
int main(){ int cnt = 10; while(cnt) { printf("这是一个倒计时:%2d ", cnt); fflush(stdout); cnt--; sleep(1); } return 0;}登录后复制
/r代表回车键;但它无法刷新缓冲区,因此我们需要手动刷新才可看到正确的倒计时显示。
- 进度条程序

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

首先,需要准备一个长度为字符数组。这样,可以确保处理任何可能的输入,并避免额外的空间开销。此代码在JavaScript中不会执行任何操作。
运行
复制
#define NUM 101char pg[NUM];memset(pg, '', sizeof(pg));登录后复制
首先,初始化这个数组,并在循环中动态赋值,通过定义一个临时变量来控制循环和改变数组中的值。记得对后面的圆点(%)进行处理,使其看上去像数字的“小圈圈”。使用JavaScript编写的代码将执行多次,但运行次数为
运行
复制
char cir[4] = {'|', '\', '-', '/'};int cnt = 0; while(cnt <= 100) { printf("[%-100s][%d%%][%c] ", pg, cnt, cir[cnt % 4]); fflush(stdout); pg[cnt++] = STYLE; usleep(50000); }登录后复制
对于fflush,与sleep上面的例子不再赘述。至于usleep是为了加快进程速度,使其在内完成循环,每次间隔为秒(即。因此,根据usleep的值计算,秒即等于。
?三、总结
本篇博客我们详细探讨了Linux调试器gdb及进程进度条程序的技术要点。gdb是一款功能强大的命令行源代码级调试器,能够为多种编程语言提供全面的调试支持,广泛应用于Linux等系统中。通过示例代码展示了其基本使用方法:设置断点、查看变量等。此外,文章重点讲解了如何在Linux环境下实现进度条显示,包括使用printf缓冲机制以及利用相关函数动态展示进度效果。希望读者能够从中获益良多!
以上就是【Linux】想学习Linux不看这一篇你就慢了-->工具篇(四)gdb、进度条程序的详细内容,更多请关注其它相关文章!
