首页 > 运维 > linux运维 > 正文

深度解析如何在Linux中创建自己的第一个系统程序---进度条

看不見的法師
发布: 2025-04-17 14:46:01
原创
763人浏览过

&&

在我们的编译器里面我们只想 进行回车的话,那么我们就是

我们之前在vs2022里面的 是回车且换行

但是今天我们的这里的 和在这个不是一个概念

其实回车换行其实是两个动作的

行缓冲区

我们第一个进行编译的时候我们加上 ,然后sleep两秒

我们编译运行可以发现我们的打印内容先出来然后进行等待两秒

但是我们将这个 去掉的话,我们发现编译的时候是等到了两秒,这个打印的内容才出来的

深度解析如何在Linux中创建自己的第一个系统程序---进度条

我们带 的话就是数据立即显示

那么我们如果不带 的话我们先执行printf还是sleep呢?

我们c语言一定是从上到下进行执行的

那么我们这里也是先执行printf也是执行sleep的

那么我们打印的数据怎么没看见呢?

那么我们这时候的数据肯定是存在缓冲区里面的

等休眠时间结束了,我们就将我们打印的显示出来

只要有缓冲区的话

那么一定存在这个刷新策略

显示器的刷新策略:行刷新!

所以如果包含 的话立即打印到显示器上

如果不包含的话改字符串不做刷新,要么程序要么结束自动刷新,要么我们进行强制刷新的操作

如果我们想让不带 的消息进行刷新的话怎么办呢?

我们可以使用命令fflush

深度解析如何在Linux中创建自己的第一个系统程序---进度条

这个命令可以直接进行强制刷新的操作

我们在代码中添加这个代码就能立即进行刷新的操作

代码语言:javascript代码运行次数:0运行复制
#include <stdio.h>  2 #include<unistd.h>  3   4 int main()  5 {  6   printf("hello kaikai");  7   fflush(stdout);//利用这个文件流将我们的字符串立即进行刷新的操作         8   sleep(2);                                                         9   return 0;                                                        10 }     
登录后复制
深度解析如何在Linux中创建自己的第一个系统程序---进度条

然后我们运行程序我们可以发现字符串立即被打印出来了

我们现在对code.c进行编辑

我们想让结果在一行进行显示的操作

但是我们最后呈现出来的是很多行

深度解析如何在Linux中创建自己的第一个系统程序---进度条
深度解析如何在Linux中创建自己的第一个系统程序---进度条

那么怎么样让我们的光标在写完之后重新回到那一行呢?

我们可以将原来的 换成我们的 就行了

的作用是在输出完毕之后光标能够回到最开始的位置

深度解析如何在Linux中创建自己的第一个系统程序---进度条

但是我们又发现这个什么都不打印

深度解析如何在Linux中创建自己的第一个系统程序---进度条

因为我们这里后面不是 了,不会进行刷新操作的,我们打印的结果都是显示在缓冲区里面的

那么我们就进行主动刷新的操作

我们在代码的后面加上fflush(stdout);就行了

输出后我们立即进行刷新,将我们的数字显示出来

但是我们发现我们的数字一打印完就会消失了,光标一直回到开头

最后被命令行覆盖了

深度解析如何在Linux中创建自己的第一个系统程序---进度条
深度解析如何在Linux中创建自己的第一个系统程序---进度条

我们可以在代码的最后加上这个 进行换行的操作

那么这里我们就完成了一个倒计时的装置了

代码语言:javascript代码运行次数:0运行复制
#include <stdio.h>  2 #include<unistd.h>  3   4 int main()  5 {  6   int cnt=9;  7   while(cnt>=0)  8   {  9     printf("%d
",cnt); 10     fflush(stdout);//利用这个文件流将我们的字符串立即进行刷新的操作 11     cnt--; 12     sleep(1); 13   } 14   printf("
");                                                          15 //  printf("hello kaikai"); 16 //  fflush(stdout);//利用这个文件流将我们的字符串立即进行刷新的操作 17 //  sleep(2); 18   return 0; 19 }~     
登录后复制
深度解析如何在Linux中创建自己的第一个系统程序---进度条

最终效果就是到了0我们就直接进行了换行的操作了

深度解析如何在Linux中创建自己的第一个系统程序---进度条

但是我们又发现我们将这个cnt初始化为10的话我们最后打印的就是这样的

会在后面带上一个0,这是为什么呢?

深度解析如何在Linux中创建自己的第一个系统程序---进度条

其实显示器只认字符的

我们在打印的其实是以字符为单位进行打印的操作

我们第一个答应的是1和0两个字符

那么第二次的时候我们的光标回到第一个字符了

然后我们打印9

但是我们之前的字符0没有删除

所以显示的就是90

80

70

60

等等

那么我们怎么进行修改操作呢?

我们可以在我们的格式化那里进行修改的操作的

我们改变成%2d就行了

深度解析如何在Linux中创建自己的第一个系统程序---进度条

但是我们发现我们的这个空格打印的时候在左侧的,我们想让不足2位的空格在右边

深度解析如何在Linux中创建自己的第一个系统程序---进度条

那么我们怎么办?

我们是可以使用%-2d进行调整

因为我们格式化的时候,,不足位置的时候默认是右对齐的

那么我们加上-号就可以变成左对齐了

那么到这里我们就实现成功了

深度解析如何在Linux中创建自己的第一个系统程序---进度条
进度条实现

我们的Linux中的进度条通常是这样的

深度解析如何在Linux中创建自己的第一个系统程序---进度条

随着进步不断增加,我们括号中的#就会增加,右边的数字也是显示的进度

然后右边的斜杠就是我们的光标移动

我们这里声明在.h文件中,实现在.c文件中,然后我们在main.c中进行编译操作

深度解析如何在Linux中创建自己的第一个系统程序---进度条

我们将我们的Makefile文件拷贝到当前的目录中

使用命令cp ../Makefile .将上级目录中的Makefile文件拷贝到当前的文件中

那么这样我们就成功了

深度解析如何在Linux中创建自己的第一个系统程序---进度条

我们只需要将这个Makefile里面的BIN就是生成的可执行文件的名称进行改变下就行了,其他的不需要进行变化

深度解析如何在Linux中创建自己的第一个系统程序---进度条

我们然后进行正常的编译操作,输入命令make

深度解析如何在Linux中创建自己的第一个系统程序---进度条

我们在这里面引用了usleep的概念

下面的具体的使用方法

usleep 是一个 C 语言中的函数,定义在 头文件中,用于让程序暂停执行一段时间(微秒级别)。它的作用是引入延时,通常在需要控制程序执行速度或等待某些事件的场景下使用。


函数原型:代码语言:javascript代码运行次数:0运行复制
int usleep(useconds_t usec);
登录后复制
参数: usec:延时的时间,以微秒(microseconds)为单位。1 秒 = 1,000,000 微秒。 返回值: 成功时返回 0。 如果出错(例如传入了非法参数),则返回 -1 并设置 errno。

使用场景:控制程序的执行速度: 在循环中延时一定时间,避免程序执行得过快。 常用于动画、进度条、实时更新等。 等待硬件或外部事件:等待特定硬件响应,比如 GPIO 信号稳定。减少 CPU 占用率:在多线程程序中,为线程设置短暂的休眠以释放 CPU 资源。

示例:

以下是一个简单的例子,展示如何使用 usleep 实现动态进度条:

代码语言:javascript代码运行次数:0运行复制
#include <stdio.h>#include <unistd.h> // 包含 usleep 函数int main() {    printf("Loading...
");    for (int i = 0; i <= 100; i++) {        printf("
Progress: %d%%", i); // 使用 
 覆盖上一行        fflush(stdout);               // 刷新输出缓冲区        usleep(50000);                // 延时 50,000 微秒(50 毫秒)    }    printf("
Done!
");    return 0;}
登录后复制

运行效果: 程序每 50 毫秒更新一次,显示动态的进度条效果。


注意事项:跨平台兼容性: usleep 是 POSIX 标准的一部分,因此在 Windows 平台上可能无法使用。如果需要跨平台的延时功能,可以使用其他方法,比如: Sleep 函数(Windows 特有,单位为毫秒)。 nanosleep(更精确的 POSIX 延时函数)。 std::this_thread::sleep_for(C++11 标准库,适用于跨平台)。 延时的精度:usleep 的精度依赖于操作系统调度器。在某些情况下,实际延时可能比指定时间更长,尤其是在多任务系统中。不推荐使用(现代 POSIX):在 POSIX.1-2008 标准中,usleep 已被标记为不推荐使用(deprecated),建议使用更精确的 nanosleep 或 clock_nanosleep。

替代方法(使用 nanosleep):代码语言:javascript代码运行次数:0运行复制
#include <stdio.h>#include <time.h>int main() {    struct timespec ts;    ts.tv_sec = 0;         // 秒    ts.tv_nsec = 50000000; // 纳秒(50 毫秒)    printf("Loading...
");    for (int i = 0; i <= 100; i++) {        printf("
Progress: %d%%", i);        fflush(stdout);        nanosleep(&ts, NULL); // 延时 50 毫秒    }    printf("
Done!
");    return 0;}
登录后复制

这提供了更高的精度和可靠性。

那么到这里我们就能通过下面的代码进行进度的显示了

代码语言:javascript代码运行次数:0运行复制
 #include"process.h"  2 #include<string.h>  3 #include<unistd.h>  4 #define SIZE 101   5 #define STYLE '#'  6 void process()  7 {  8   //v1版本展示进度条的基本功能  9   int rate=0; 10   //定义一个缓冲区 11   char buffer[SIZE]; 12   memset(buffer,0,sizeof(buffer));//将我们的buffer初始化为0 13   while(rate<=100) 14   {              15     printf("[%s]
",buffer);//每次从我们的当前行开始输出 16     fflush(stdout);//将我们缓冲区的消息进行刷新操作 17     buffer[rate]=STYLE; 18     rate++;                                   19     usleep(50000); 20   } 21   printf("
");//让我们左侧的命令行新起一行                              22 }                                             ~     
登录后复制
深度解析如何在Linux中创建自己的第一个系统程序---进度条
深度解析如何在Linux中创建自己的第一个系统程序---进度条

但是我们这个进度条的右侧的中扩号不是固定的,而是随着#的增加而往右边进行移动的

所以我们必须预留出足够大的空间来进行#的填充操作

所以这个右括号不应该随着进度条的移动而移动

我们将代码改成这样子,将位置预留出来,然后加上-号向左对齐就行了

深度解析如何在Linux中创建自己的第一个系统程序---进度条

那么最后我们代码就完成了

深度解析如何在Linux中创建自己的第一个系统程序---进度条
代码语言:javascript代码运行次数:0运行复制
 1 #include"process.h"  2 #include<string.h>  3 #include<unistd.h>  4 #define SIZE 101   5 #define STYLE '#'  6 void process()  7 {  8   //v1版本展示进度条的基本功能  9   int rate=0; 10   //定义一个缓冲区 11   char buffer[SIZE]; 12   memset(buffer,0,sizeof(buffer));//将我们的buffer初始化为0 13   const char*lable="|/-\";                                                                                                                                                                    14   int len =strlen(lable); 15  16   while(rate<=100) 17   { 18     printf("[%-100s][%d%%][%c]
",buffer,rate,lable[rate%len]);//每次从我们的当前行开始输出,rate%len就是最后显示的下标只可能是 0 1 2 3这四个数,可以使我们的四个字符一直进行变化的操作 19     fflush(stdout);//将我们缓冲区的消息进行刷新操作 20     buffer[rate]=STYLE; 21     rate++; 22     usleep(50000);                                                                           23   }                                                  24   printf("
");//让我们左侧的命令行新起一行   25 }                  ~
登录后复制

但是这个进度条我们没办法直接进行使用的操作

我们正常的进度条是随着这个下载的量而使这个进度条进行增加

而不是一次性将这个进度条打完

我们这个进度条应该是随着我们的下载的数据量进行推进的

最后的代码就是这样的

main.c

代码语言:javascript代码运行次数:0运行复制
#include"process.h"    2 #include<unistd.h>    3 #include<time.h>    4 #include<stdlib.h>    5 //定义一个函数指针类型    6 typedef void (*call_t)(const char*,double,double);//定义了一个函数指针      的类型    7     8 double total=1024.0;//一共要下载的总量    9 //double speed=1.0;//定义一个网速   10 double speed[]={1.0,0.5,1.2,0.01,0.02};//定义一个网速清单   11    12 //下载   13 //回调函数   14 void download(int total,call_t cb)   15 {   16   srand(time(NULL));   17   double current=0.0;   18   while(current<=total)   19   {   20     //更新进度   21     cb("下载",total,current);//进行回调   22     if(current>=total) break;   23     //下载代码   24     int random=rand()%5;   25     usleep(50000);   26    27     current+=speed[random];   28     if(current>=total)                                                   29     {   30       current=total;   31     }   32   }//加上随机数进行动态的调整操作33 }   34 void uploadload(int total,call_t cb)   35 {   36   srand(time(NULL));   37   double current=0.0;   38   while(current<=total)   39   {                                                                      40     //更新进度   41     cb("上传中",total,current);//进行回调   42     if(current>=total) break;   43     //下载代码   44     int random=rand()%5;   45     usleep(50000);   46    47     current+=speed[random];   48     if(current>=total)   49     {   50       current=total;   51     }   52   }//加上随机数进行动态的调整操作   53 }   54 int main()E> 55 {   56   download(1024.0,FlushProcess);   57   printf("download 1024.0MB done
");   58   download(512.0,FlushProcess);   59   printf("download 512.0MB done
");   60   download(334.0,FlushProcess);   61   printf("download 334.0MB done
");   62   //process();   63   download(64.0,FlushProcess);   64   printf("download 64.0MB done
");   65   return 0;   66  }
登录后复制

process.c

代码语言:javascript代码运行次数:0运行复制
#include"process.h"  2 #include<string.h>  3 #include<unistd.h>  4 #define SIZE 101   5 #define STYLE '#'  6 //v2:根据进度进行动态刷新一次我们的进度条  7 void FlushProcess(const char*tips,double total,double current)  8 {  9   const char*lable="|/-\"; 10   int len=strlen(lable); 11   static int index=0;//只要我们调用这整个函数的话,那么我们这个光标就能>    进行转动的操作了 12   char buffer[SIZE]; 13   memset(buffer,0,sizeof(buffer));//将我们的buffer初始化为0 14                                      15   //int num =(int)(current*100/total);//只要满足到了1个#的话那么我们就进    行数据的刷新 16   double rate = current*100.0/total; 17   int num=(int)rate;//我们的num直接通过我们的比率进行获得 18   int i=0;           19   for(;i<num;i++) 20   { 21     buffer[i]=STYLE; 22   }                        23                                     24   printf("%s...[%-100s][%.1lf%%][%c]
",tips,buffer,rate,lable[index++])    ;//100s就是预留出100个位置 25   fflush(stdout);//强制进行刷新操作 26   index%=len;//保证我们的index不会发现越界的现象                         27   if(num==100) 28   { 29     printf("
"); 30   }      31 }//即使我们的进度条不进行更新操作,我们依旧在进行下载的进度中,光标是一直    在旋转的 33                                                                          34  35 void process() 36 { 37   //v1版本展示进度条的基本功能 38   int rate=0; 39   //定义一个缓冲区 40   char buffer[SIZE]; 41   memset(buffer,0,sizeof(buffer));//将我们的buffer初始化为0 42   const char*lable="|/-\"; 43   int len =strlen(lable); 44    45   while(rate<=100) 46   { 47     printf("[%-100s][%d%%][%c]
",buffer,rate,lable[rate%len]);//每次从>    我们的当前行开始输出,rate%len就是最后显示的下标只可能是 0 1 2 3这四个数>    ,可以使我们的四个字符一直进行变化的操作 48     fflush(stdout);//将我们缓冲区的消息进行刷新操作 49     buffer[rate]=STYLE; 50     rate++; 51     usleep(50000); 52   } 53   printf("
");//让我们左侧的命令行新起一行 54 }
登录后复制

process.h

代码语言:javascript代码运行次数:0运行复制
#pragma once    2 #include<stdio.h>  3 //v1版本  4 void process();  5   6 //v2版本  7 //根据当前的量以及总量进行当前进度条的刷新操作  8 void FlushProcess(const char*tips,double total,double current); 
登录后复制

以上就是深度解析如何在Linux中创建自己的第一个系统程序---进度条的详细内容,更多请关注php中文网其它相关文章!

最佳 Windows 性能的顶级免费优化软件
最佳 Windows 性能的顶级免费优化软件

每个人都需要一台速度更快、更稳定的 PC。随着时间的推移,垃圾文件、旧注册表数据和不必要的后台进程会占用资源并降低性能。幸运的是,许多工具可以让 Windows 保持平稳运行。

下载
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn
最新问题
开源免费商场系统广告
热门教程
更多>
最新下载
更多>
网站特效
网站源码
网站素材
前端模板
关于我们 免责申明 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送
PHP中文网APP
随时随地碎片化学习
PHP中文网抖音号
发现有趣的

Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号