业务网站在线生成,简述网站推广的方式,廊坊购物网站开发设计,网站专题框架怎么做Linux从0到1——Linux第一个小程序#xff1a;进度条 1. 输出缓冲区2. 回车和换行的本质3. 实现进度条3.1 简单原理版本3.2 实际工程版本 1. 输出缓冲区 1. 小实验#xff1a;
编写一个test.c文件#xff0c;#xff1a;
#include stdio.h
#include unistd.h… Linux从0到1——Linux第一个小程序进度条 1. 输出缓冲区2. 回车和换行的本质3. 实现进度条3.1 简单原理版本3.2 实际工程版本 1. 输出缓冲区 1. 小实验
编写一个test.c文件
#include stdio.h
#include unistd.hint main()
{printf(你能看见我吗\n);sleep(1); // 暂停1秒return 0;
}编译并执行 先打印然后暂停一秒结束程序很好理解。
2. 发现问题
修改test.c文件内容如下 再次编译并执行 发现运行可执行程序后没有直接打印内容而是隔了一秒钟才打印这好像和我们理解的不太一样是怎么回事
我们可以确定的是一定是printf先执行的因为C语言代码一定是从上到下运行的但是现象是字符没有打印。所以我们可以断定printf其实早就运行了只不过在sleep期间字符串没有被显示出来。在sleep期间字符串在输出缓冲区当中。
3. 缓冲区
C/C语言会针对标准输出给我们提供默认的缓冲区(stdout)。我们可以使用fflush函数可以把一个流强制做刷新标准输入输出流之后会讲这里只需要知道它可以刷新输出缓冲区。
验证 编译并执行 那为什么加\n的程序不需要刷新缓冲区这是因为\n是一种刷新策略叫行刷新默认就有刷新缓冲区的功能。 2. 回车和换行的本质 我们来写一个倒计时程序
#include stdio.h
#include unistd.hint main()
{int cnt 9;while(cnt){printf(%d\n, cnt);cnt--;sleep(1);}return 0;
}运行一下 可以发现它是换行打印倒计时但是我们想让它只在一行打印并且覆盖掉前一秒的秒数如何做\n是换行加回车我们现在的需求是只回车不换行可以通过\r实现但是\r没有刷新缓冲区的功能。
修改如下 运行一下 3. 实现进度条 3.1 简单原理版本 1. 原理讲解
我们期望的进度条形式如下 进度条的风格是#右侧有一个百分数提示当前具体进度还有一个旋转光标可以确定当进度条不动时进程是还在进行还是卡住了。
进度条的实现第一次输出#第二次输出##一次类推#越来越多。为了实现图中结果我们可以通过不断回车然后覆盖之前的#实现比如用##覆盖#旋转光标的实现利用一个常量字符串实现让字符在|/-\这几个字符按顺序不断转换实现旋转效果。
2. 文件准备 main.c文件是主函数所在文件进度条的具体实现在process.c文件中主函数文件通过头文件process.h调用进度条的实现函数各个文件内容如下最重要是process.c。
process.c文件
#include process.h
#include unistd.h // sleep的头文件
#include string.h#define SIZE 101
#define MAX_RATE 100
#define STYLE #
#define STIME 1000*40const char* str|/-\\; // 旋转光标void process()
{// version 1int rate 0;char bar[SIZE] {0}; // 全部初始化成\0int num strlen(str);while(rate MAX_RATE){printf([%-100s][%d%%][%c]\r, bar, rate, str[rate%num]); // 打印百分号最好用%%fflush(stdout);usleep(STIME); // 单位是u秒bar[rate] STYLE;}printf(\n);
}main.c文件
#include process.h int main()
{process();return 0;
}process.h文件
#pragma once#include stdio.h void process();编辑Makefile 3.2 实际工程版本 无论是任何进度条一定是和某种任务关联的
process.c文件
#include process.hconst char* str|/-\\; // 旋转光标void process_v1()
{// version 1int rate 0;char bar[SIZE] {0}; // 全部初始化成\0int num strlen(str);while(rate MAX_RATE){printf([%-100s][%d%%][%c]\r, bar, rate, str[rate%num]); // 打印百分号最好用%%fflush(stdout);usleep(STIME); // 单位是u秒bar[rate] STYLE;}printf(\n);
}// 不能一次将进度条打印完毕否则无法平滑的和场景结合
// 该函数应该根据rate自动的打一次
void process_v2(int rate)
{ // version 2static char bar[SIZE] {0}; int num strlen(str);if(rate MAX_RATE rate 0){printf([%-100s][%d%%][%c]\r, bar, rate, str[rate%num]); // 打印百分号最好用%%fflush(stdout);bar[rate] STYLE;}if(rate MAX_RATE) memset(bar, \0, sizeof(bar));
}process.h文件
#pragma once#include string.h
#include stdio.h
#include unistd.h#define SIZE 101
#define MAX_RATE 100
#define STYLE #
#define STIME 1000*40// 定义了一个函数指针类型其中函数的参数是int返回值是void
typedef void callback_t(int);void process_v1();
void process_v2(int);main.c文件
#include process.h#define TARGET_SIZE 1024*1024 // 1MB下载软件总大小
#define DSIZE 1024*10 // 模拟每次下载的单位大小// 下载软件
void download(callback_t cb)
{int target TARGET_SIZE; // 下载软件总大小int total 0; // 目前下载了多少while(total target){usleep(STIME); // 用简单的休眠时间模拟本轮下载花费的时间total DSIZE;int rate total*100/target;cb(rate); // 传一个比率}printf(\n);
}int main()
{download(process_v2);return 0;
}我们希望进度条在进度条函数内部循环打印所以我们采用回调的方式来进行某种任务的通知动态更新进度条