深度解析如何在Linux中创建自己的第一个系统程序
深度解析如何在Linux中创建自己的第一个系统程序
\r&&\n
在我们的编译器里面我们只想 进行回车的话,那么我们就是\r
我们之前在vs2022里面的\n是回车且换行
但是今天我们的这里的\n和在这个不是一个概念
其实回车换行其实是两个动作的
行缓冲区
我们第一个进行编译的时候我们加上\n,然后sleep两秒
我们编译运行可以发现我们的打印内容先出来然后进行等待两秒
但是我们将这个\n去掉的话,我们发现编译的时候是等到了两秒,这个打印的内容才出来的
我们带\n的话就是数据立即显示
那么我们如果不带\n的话我们先执行printf还是sleep呢?
我们c语言一定是从上到下进行执行的
那么我们这里也是先执行printf也是执行sleep的
那么我们打印的数据怎么没看见呢?
那么我们这时候的数据肯定是存在缓冲区里面的
等休眠时间结束了,我们就将我们打印的显示出来
只要有缓冲区的话
那么一定存在这个刷新策略
显示器的刷新策略:行刷新!
所以如果包含\n的话立即打印到显示器上
如果不包含的话改字符串不做刷新,要么程序要么结束自动刷新,要么我们进行强制刷新的操作
如果我们想让不带\n的消息进行刷新的话怎么办呢?
我们可以使用命令fflush
这个命令可以直接进行强制刷新的操作
我们在代码中添加这个代码就能立即进行刷新的操作
代码语言:javascript代码运行次数:0运行复制#include <stdio.h>
2 #include<unistd.h>
4 int main()
5 {
6 printf("hello kaikai");
7 fflush(stdout);//利用这个文件流将我们的字符串立即进行刷新的操作
8 sleep(2);
9 return 0;
10 }
然后我们运行程序我们可以发现字符串立即被打印出来了
我们现在对进行编辑
我们想让结果在一行进行显示的操作
但是我们最后呈现出来的是很多行
那么怎么样让我们的光标在写完之后重新回到那一行呢?
我们可以将原来的\n换成我们的\r就行了
\r的作用是在输出完毕之后光标能够回到最开始的位置
但是我们又发现这个什么都不打印
因为我们这里后面不是\n了,不会进行刷新操作的,我们打印的结果都是显示在缓冲区里面的
那么我们就进行主动刷新的操作
我们在代码的后面加上fflush(stdout);
就行了
输出后我们立即进行刷新,将我们的数字显示出来
但是我们发现我们的数字一打印完就会消失了,光标一直回到开头
最后被命令行覆盖了
我们可以在代码的最后加上这个\n进行换行的操作
那么这里我们就完成了一个倒计时的装置了
代码语言:javascript代码运行次数:0运行复制#include <stdio.h>
2 #include<unistd.h>
4 int main()
5 {
6 int cnt=9;
7 while(cnt>=0)
8 {
9 printf("%d\r",cnt);
10 fflush(stdout);//利用这个文件流将我们的字符串立即进行刷新的操作
11 cnt--;
12 sleep(1);
1 }
14 printf("\n");
15 // printf("hello kaikai");
16 // fflush(stdout);//利用这个文件流将我们的字符串立即进行刷新的操作
17 // sleep(2);
18 return 0;
19 }
~
最终效果就是到了0我们就直接进行了换行的操作了
但是我们又发现我们将这个cnt初始化为10的话我们最后打印的就是这样的
会在后面带上一个0,这是为什么呢?
其实显示器只认字符的
我们在打印的其实是以字符为单位进行打印的操作
我们第一个答应的是1和0两个字符
那么第二次的时候我们的光标回到第一个字符了
然后我们打印9
但是我们之前的字符0没有删除
所以显示的就是90
80
70
60
等等
那么我们怎么进行修改操作呢?
我们可以在我们的格式化那里进行修改的操作的
我们改变成%2d就行了
但是我们发现我们的这个空格打印的时候在左侧的,我们想让不足2位的空格在右边
那么我们怎么办?
我们是可以使用%-2d进行调整
因为我们格式化的时候,,不足位置的时候默认是右对齐的
那么我们加上-号就可以变成左对齐了
那么到这里我们就实现成功了
进度条实现
我们的Linux中的进度条通常是这样的
随着进步不断增加,我们括号中的#就会增加,右边的数字也是显示的进度
然后右边的斜杠就是我们的光标移动
我们这里声明在.件中,实现在.c文件中,然后我们在中进行编译操作
我们将我们的Makefile文件拷贝到当前的目录中
使用命令cp ../Makefile .
将上级目录中的Makefile文件拷贝到当前的文件中
那么这样我们就成功了
我们只需要将这个Makefile里面的BI就是生成的可执行文件的名称进行改变下就行了,其他的不需要进行变化
我们然后进行正常的编译操作,输入命令make
我们在这里面引用了usleep的概念
下面的具体的使用方法
usleep
是一个 C 语言中的函数,定义在 <unistd.h>
头文件中,用于让程序暂停执行一段时间(微秒级别)。它的作用是引入延时,通常在需要控制程序执行速度或等待某些事件的场景下使用。
函数原型:
代码语言:javascript代码运行次数:0运行复制int usleep(useconds_t usec);
- 参数:
usec
:延时的时间,以微秒(microseconds)为单位。1 秒 = 1,000,000 微秒。
- 返回值:
- 成功时返回
0
。 - 如果出错(例如传入了非法参数),则返回
-1
并设置errno
。
- 成功时返回
使用场景:
- 控制程序的执行速度:
- 在循环中延时一定时间,避免程序执行得过快。
- 常用于动画、进度条、实时更新等。
- 等待硬件或外部事件:
- 等待特定硬件响应,比如 GPIO 信号稳定。
- 减少 CPU 占用率:
- 在多线程程序中,为线程设置短暂的休眠以释放 CPU 资源。
示例:
以下是一个简单的例子,展示如何使用 usleep
实现动态进度条:
#include <stdio.h>
#include <unistd.h> // 包含 usleep 函数
int main() {
printf("Loading...\n");
for (int i = 0; i <= 100; i++) {
printf("\rProgress: %d%%", i); // 使用 \r 覆盖上一行
fflush(stdout); // 刷新输出缓冲区
usleep(50000); // 延时 50,000 微秒(50 毫秒)
}
printf("\nDone!\n");
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;
_sec = 0; // 秒
_nsec = 50000000; // 纳秒(50 毫秒)
printf("Loading...\n");
for (int i = 0; i <= 100; i++) {
printf("\rProgress: %d%%", i);
fflush(stdout);
nanosleep(&ts, ULL); // 延时 50 毫秒
}
printf("\nDone!\n");
return 0;
}
这提供了更高的精度和可靠性。
那么到这里我们就能通过下面的代码进行进度的显示了
代码语言:javascript代码运行次数:0运行复制 #include"process.h"
2 #include<string.h>
#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
1 while(rate<=100)
14 {
15 printf("[%s]\r",buffer);//每次从我们的当前行开始输出
16 fflush(stdout);//将我们缓冲区的消息进行刷新操作
17 buffer[rate]=STYLE;
18 rate++;
19 usleep(50000);
20 }
21 printf("\n");//让我们左侧的命令行新起一行
22 }
~
但是我们这个进度条的右侧的中扩号不是固定的,而是随着#的增加而往右边进行移动的
所以我们必须预留出足够大的空间来进行#的填充操作
所以这个右括号不应该随着进度条的移动而移动
我们将代码改成这样子,将位置预留出来,然后加上-号向左对齐就行了
那么最后我们代码就完成了
1 #include"process.h"
2 #include<string.h>
#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
1 ct char*lable="|/-\\";
14 int len =strlen(lable);
15
16 while(rate<=100)
17 {
18 printf("[%-100s][%d%%][%c]\r",buffer,rate,lable[rate%len]);//每次从我们的当前行开始输出,rate%len就是最后显示的下标只可能是 0 1 2 这四个数,可以使我们的四个字符一直进行变化的操作
19 fflush(stdout);//将我们缓冲区的消息进行刷新操作
20 buffer[rate]=STYLE;
21 rate++;
22 usleep(50000);
2 }
24 printf("\n");//让我们左侧的命令行新起一行
25 }
~
但是这个进度条我们没办法直接进行使用的操作
我们正常的进度条是随着这个下载的量而使这个进度条进行增加
而不是一次性将这个进度条打完
我们这个进度条应该是随着我们的下载的数据量进行推进的
最后的代码就是这样的
代码语言:javascript代码运行次数:0运行复制#include"process.h"
2 #include<unistd.h>
#include<time.h>
4 #include<stdlib.h>
5 //定义一个函数指针类型
6 typedef void (*call_t)(ct 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 //下载
1 //回调函数
14 void download(int total,call_t cb)
15 {
16 srand(time(ULL));
17 double current=0.0;
18 while(current<=total)
19 {
20 //更新进度
21 cb("下载",total,current);//进行回调
22 if(current>=total) break;
2 //下载代码
24 int random=rand()%5;
25 usleep(50000);
26
27 current+=speed[random];
28 if(current>=total)
29 {
0 current=total;
1 }
2 }//加上随机数进行动态的调整操作
}
4 void uploadload(int total,call_t cb)
5 {
6 srand(time(ULL));
7 double current=0.0;
8 while(current<=total)
9 {
40 //更新进度
41 cb("上传中",total,current);//进行回调
42 if(current>=total) break;
4 //下载代码
44 int random=rand()%5;
45 usleep(50000);
46
47 current+=speed[random];
48 if(current>=total)
49 {
50 current=total;
51 }
52 }//加上随机数进行动态的调整操作
5 }
54 int main()
E> 55 {
56 download(1024.0,FlushProcess);
57 printf("download 1024.0MB done\n");
58 download(512.0,FlushProcess);
59 printf("download 512.0MB done\n");
60 download(4.0,FlushProcess);
61 printf("download 4.0MB done\n");
62 //process();
6 download(64.0,FlushProcess);
64 printf("download 64.0MB done\n");
65 return 0;
66 }
代码语言:javascript代码运行次数:0运行复制#include"process.h"
2 #include<string.h>
#include<unistd.h>
4 #define SIZE 101
5 #define STYLE '#'
6 //v2:根据进度进行动态刷新一次我们的进度条
7 void FlushProcess(ct char*tips,double total,double current)
8 { 9 ct char*lable="|/-\\";
10 int len=strlen(lable);
11 static int index=0;//只要我们调用这整个函数的话,那么我们这个光标就能> 进行转动的操作了
12 char buffer[SIZE]; 1 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 }
2
24 printf("%s...[%-100s][%.1lf%%][%c]\r",tips,buffer,rate,lable[index++]) ;//100s就是预留出100个位置
25 fflush(stdout);//强制进行刷新操作
26 index%=len;//保证我们的index不会发现越界的现象
27 if(num==100)
28 {
29 printf("\n"); 0 }
1 }
//即使我们的进度条不进行更新操作,我们依旧在进行下载的进度中,光标是一直 在旋转的
4
5 void process()
6 {
7 //v1版本展示进度条的基本功能
8 int rate=0;
9 //定义一个缓冲区
40 char buffer[SIZE];
41 memset(buffer,0,sizeof(buffer));//将我们的buffer初始化为0
42 ct char*lable="|/-\\";
4 int len =strlen(lable);
44
45 while(rate<=100)
46 {
47 printf("[%-100s][%d%%][%c]\r",buffer,rate,lable[rate%len]);//每次从> 我们的当前行开始输出,rate%len就是最后显示的下标只可能是 0 1 2 这四个数> ,可以使我们的四个字符一直进行变化的操作
48 fflush(stdout);//将我们缓冲区的消息进行刷新操作
49 buffer[rate]=STYLE;
50 rate++;
51 usleep(50000);
52 }
5 printf("\n");//让我们左侧的命令行新起一行
54 }
process.h
代码语言:javascript代码运行次数:0运行复制#pragma once
2 #include<stdio.h>
//v1版本
4 void process();
5
6 //v2版本
7 //根据当前的量以及总量进行当前进度条的刷新操作
8 void FlushProcess(ct char*tips,double total,double current);
本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。 原始发表:2025-01-17,如有侵权请联系 cloudcommunity@tencent 删除程序函数系统字符串linux #感谢您对电脑配置推荐网 - 最新i3 i5 i7组装电脑配置单推荐报价格的认可,转载请说明来源于"电脑配置推荐网 - 最新i3 i5 i7组装电脑配置单推荐报价格
推荐阅读
留言与评论(共有 20 条评论) |
本站网友 不吃晚饭能减肥吗 | 12分钟前 发表 |
注意事项:跨平台兼容性: usleep 是 POSIX 标准的一部分 | |
本站网友 异味 | 10分钟前 发表 |
然后加上-号向左对齐就行了 那么最后我们代码就完成了代码语言:javascript代码运行次数:0运行复制 1 #include"process.h" 2 #include<string.h> #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 | |
本站网友 北斗手机网站 | 4分钟前 发表 |
在某些情况下 | |
本站网友 丰田aygo | 14分钟前 发表 |
rate | |
本站网友 便秘的症状 | 6分钟前 发表 |
rate | |
本站网友 理财产品 | 22分钟前 发表 |
在某些情况下 | |
本站网友 北京哮喘医院 | 18分钟前 发表 |
rate%len就是最后显示的下标只可能是 0 1 2 这四个数 | |
本站网友 dma指标 | 11分钟前 发表 |
我们发现编译的时候是等到了两秒 | |
本站网友 快速美白肌肤 | 6分钟前 发表 |
rate%len就是最后显示的下标只可能是 0 1 2 这四个数 | |
本站网友 大锅饭 | 4分钟前 发表 |
根据进度进行动态刷新一次我们的进度条 7 void FlushProcess(ct char*tips | |
本站网友 怎么治脚气 | 17分钟前 发表 |
使用场景:控制程序的执行速度: 在循环中延时一定时间 | |
本站网友 英达家族 | 12分钟前 发表 |
这个打印的内容才出来的 我们带\n的话就是数据立即显示那么我们如果不带\n的话我们先执行printf还是sleep呢?我们c语言一定是从上到下进行执行的那么我们这里也是先执行printf也是执行sleep的那么我们打印的数据怎么没看见呢?那么我们这时候的数据肯定是存在缓冲区里面的等休眠时间结束了 | |
本站网友 喝蜂蜜水的最佳时间表 | 3分钟前 发表 |
000 微秒 | |
本站网友 宝路狗粮 | 25分钟前 发表 |
不推荐使用(现代 POSIX):在 POSIX.1-2008 标准中 | |
本站网友 北京寄宿学校 | 23分钟前 发表 |
示例:以下是一个简单的例子 | |
本站网友 笋岗二手房 | 13分钟前 发表 |
double current) 8 { 9 ct char*lable="|/-\\"; 10 int len=strlen(lable); 11 static int index=0;//只要我们调用这整个函数的话 | |
本站网友 象牙山温泉度假村 | 18分钟前 发表 |
比如: Sleep 函数(Windows 特有 | |
本站网友 西玛表单 | 28分钟前 发表 |
光标一直回到开头最后被命令行覆盖了我们可以在代码的最后加上这个\n进行换行的操作那么这里我们就完成了一个倒计时的装置了代码语言:javascript代码运行次数:0运行复制#include <stdio.h> 2 #include<unistd.h> 4 int main() 5 { 6 int cnt=9; 7 while(cnt>=0) 8 { 9 printf("%d\r" | |
本站网友 中阴身 | 13分钟前 发表 |
total |