📙 作者简介 :RO-BERRY
📗 学习方向:致力于C、C++、数据结构、TCP/IP、数据库等等一系列知识
📒 日后方向 : 偏向于CPP开发以及大数据方向,欢迎各位关注,谢谢各位的支持
1.缓冲区
-
第一种情况
执行结果如下:
可以看到程序先执行printf再执行sleep -
第二种情况
执行结果如下:
在这里为什么程序先执行sleep在执行printf呢?
实际上也并没有先执行sleep再执行printf,C语言执行代码是顺序结构自上往下
在这里运行的时候,程序运行sleep的时候printf早就运行完毕了
我们程序休眠之前没有看到字符串,那么我们输出的字符串一定是被保护起来了,在退出的时候才刷新出来
那么在sleep期间在哪里保存呢?
下面我们引出一个概念- - -缓冲区。
其实上面的现象中,在程序执行 printf 后,printf 打印的内容被存放到缓冲区中,在 C/C++ 中,会针对标准输出,给我们提供默认的缓冲区,而在缓冲区没有被刷新之前,我们的内容就不会被输出。
而 \n 就是一种刷新的策略 - - - 行刷新。所以我们加了 \n 后缓冲区被刷新,随即便打印出内容。
而我们没有使用 \n 的时候缓冲区并没有被刷新,但是我们可以使用 fflush(stdout) 强制刷新缓冲区,从而打印出内容,例如:
执行结果如下:
我们可以看到,缓冲区的内容被强制刷新出来了。
2)\n 和 \r
我们首先编写一个简单的倒计数程序,例如:
观察结果:
但是这并不是我们想要的倒计时,我们是期望在同一行中显示出来,所以我们不应该用 \n,其实 \n 就是我们所说的回车,就是使光标换行并回到那一行的最初位置;这时候我们就应该使用 \r,\r 就仅仅让光标回到当前行的最初位置,我们对上面的代码修改,如下:
执行结果如下:
从上面的结果可看出,我们的倒计时虽然在同一行了,但是输出的格式还是有问题,因为默认 %d 是按照一个字符的形式打印的,我们是要按照两个字符打印,所以我们仅需将%d修改为%2d即可,如下:
结果如下:
这时候就基本完成我们的倒计时了,但是倒计时到个位数的时候,前面空了一个字符,不太美观,这是因为 %2d 是默认右对齐,我们在前面加上负号,就是左对齐了,所以我们继续修改:
结果如下:
到此我们的倒计数就完成了。
3.进度条
ProgressBar.c
#include "ProgressBar.h"
const char *str = "|/-\\"; // 加载光标
void ProgressBar_v1()
{
// 当前进度
int rate = 0;
char bar[SIZE];
memset(bar, '\0', sizeof(bar));
// 加载光标的数组长度
int num = strlen(str);
// 当进度没有加载满
while(rate <= MAX_RATE)
{
printf("[%-100s][%d%%][%c]\r", bar, rate, str[rate % num]);
fflush(stdout);
usleep(STIME);
bar[rate++] = STYLE;
}
printf("\n");
}
ProgressBar.h
#include <stdio.h>
#include <unistd.h>
#include <string.h>
void ProgressBar_v1();
#define SIZE 101 //数组大小
#define MAX_RATE 100 //加载进度最大值
#define STYLE '#' //加载符号
#define STIME 1000*40 //时间
Makefile
ProgressBar:main.c ProgressBar.c
gcc -o $@ $^
.PHONY:clean
clean:
rm -f ProgressBar
main.c
#include "ProgressBar.h"
int main()
{
ProgressBar_v1();
return 0;
}
我们在使用延时函数的时候使用了 usleep 函数,它与 sleep 相比就是,sleep 中以 s 为单位;usleep 中以 us 为单位。
运行成果:
4.认识gdb
gdb是什么
gdb是一个调试程序
程序中出现的语法错误可以借助编译器解决;但逻辑错误则只能靠自己解决。实际场景中解决逻辑错误最高效的方法,就是借助调试工具对程序进行调试。
所谓调试(Debug),就是让代码一步一步慢慢执行,跟踪程序的运行过程。比如,可以让程序停在某个地方,查看当前所有变量的值,或者内存中的数据;也可以让程序一次只执行一条或者几条语句,看看程序到底执行了哪些代码。
也就是说,通过调试程序,我们可以监控程序执行的每一个细节,包括变量的值、函数的调用过程、内存中数据、线程的调度等,从而发现隐藏的错误或者低效的代码。
程序的发布方式有两种,debug模式和release模式
Linux gcc/g++出来的二进制程序,默认是release模式
要使用gdb调试,必须在源代码生成二进制程序的时候, 加上 -g 选项
debug为可以调试的版本,release为优化后的版本也就是测试版本了
Linux gcc/g++出来的是二进制文件,默认是release版本。
在VS中,我们可以按F10进入调试
在Linux我们依旧可以调试,要使用gdb调试,必须在源代码生成二进制程序的时候, 加上 -g 选项
Debug 通常称为调试版本,它包含调试信息,并且不作任何优化,便于程序员调试程序。
Release 称为发布版本,不包含调式信息,它往往是进行了各种优化,使得程序在代码大小和运行速度上都是最优的,以便用户很好地使用。
所以我们说调试就是在Debug版本的环境中,找代码中潜伏的问题的一个过程。
"Debug"和"Release"是软件开发过程中常见的两种构建(Build)配置。
- Debug(调试)配置:
Debug 配置旨在方便开发人员在代码中进行调试和排查错误。
在 Debug 模式下,编译器会生成带有调试符号信息的可执行文件,这些符号信息包含了变量名、函数名和源代码行号等,以便在调试过程中能够准确地追踪错误。
Debug 配置通常会禁用一些优化,以便在调试过程中能够更好地观察程序的行为。
此配置的构建速度较慢,生成的可执行文件较大。
- Release(发布)配置:
Release 配置旨在生成用于最终发布的、优化后的代码。
在 Release 模式下,编译器会对代码进行优化,以提高程序的执行效率和性能。
由于优化的存在,生成的可执行文件可能没有调试符号信息,并且可能会合并和删除一些不必要的代码。
Release 配置通常会启用各种优化策略,例如内联函数、循环展开和减少函数调用开销等,以提高代码的执行速度和资源利用率。
此配置的构建速度较快,生成的可执行文件较小。
在实际开发中,通常会使用 Debug 配置进行代码的开发、调试和测试,以便于快速定位和修复问题。而在准备发布软件时,会切换到 Release 配置,以生成性能更高、体积更小的最终可执行文件。
那在Linux上gcc/g++编译生成的可执行程序其实默认是release版本的,不包含调式信息,所以我们无法调式!
gdb的作用
GDB 全称“GNU symbolic debugger”,从名称上不难看出,它诞生于 GNU 计划(同时诞生的还有 GCC、Emacs 等),是 Linux 下常用的程序调试器。发展至今,GDB 已经迭代了诸多个版本,当下的 GDB 支持调试多种编程语言编写的程序,包括 C、C++、Go、Objective-C、OpenCL、Ada等。实际场景中,GDB 更常用来调试 C 和 C++程序。
总的来说,借助 GDB调试器可以实现以下几个功能:
- 程序启动时,可以按照我们自定义的要求运行程序,例如设置参数和环境变量;
- 可使被调试程序在指定代码处暂停运行,并查看当前程序的运行状态(例如当前变量的值,函数的执行结果等),即支持断点调试;
- 程序执行过程中,可以改变某个变量的值,还可以改变代码的执行顺序,从而尝试修改程序中出现的逻辑错误。
5、gdb的使用
GDB安装
1、通过包管理器进行安装
$ yum -y install gdb
2、源码安装GDB
在gdb源码包上面下载相应的版本进行安装即可。
3、查看GDB版本
输入
gdb -v
,即可查看当前安装的gdb的版本。
如果显示出gdb的版本,也说明了安装成功。
GDB的用法
GDB 的主要功能就是监控程序的执行流程。这也就意味着,只有当源程序文件编译为可执行文件并执行时,并且该文件中必须包含必要的调试信息(比如各行代码所在的行号、包含程序中所有变量名称的列表(又称为符号表)等),GDB才会派上用场。文章来源:https://www.toymoban.com/news/detail-836009.html
所以在编译时需要使用 gcc/g++ -g 选项编译源文件,才可生成满足 GDB 要求的可执行文件
gdb常用指令:文章来源地址https://www.toymoban.com/news/detail-836009.html
- list/l 行号:显示binFile源代码,接着上次的位置往下列,每次列10行。
- list/l 函数名:列出某个函数的源代码。
- r或run:运行程序。
- n 或 next:单条执行(逐过程执行)。
- s或step:进入函数调用(逐语句执行)
- break(b) 行号:在某一行设置断点 break 函数名:在某个函数开头设置断点
- d 编号 :删除断点
- info break :查看断点信息。
- finish:执行到当前函数返回,然后停下来等待命令
- print§:打印表达式的值,通过表达式可以修改变量的值或者调用函数
- p 变量:打印变量值。
- set var:修改变量的值
- continue(或c):从当前位置开始连续而非单步执行程序
- run(或r):从开始连续而非单步执行程序
- delete breakpoints:删除所有断点
- delete breakpoints n:删除序号为n的断点
- disable breakpoints:禁用断点
- enable breakpoints:启用断点
- info(或i) breakpoints:参看当前设置了哪些断点
- display 变量名:跟踪查看一个变量,每次停下来都显示它的值
- undisplay:取消对先前设置的那些变量的跟踪
- until X行号:跳至X行
- breaktrace(或bt):查看各级函数调用及参数
- info(i) locals:查看当前栈帧局部变量的值
- quit:退出gdb=
到了这里,关于[linux开发工具]小程序--进度条、调试器 - gdb的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!