当前位置: 首页 > news >正文

Linux第一个系统程序——进度条

在这里插入图片描述

1.回车与换行

回车(CR, \r):

  • 作用:将光标移动到当前行的行首(最左侧),但不换到下一行。
  • 历史来源:源自打字机的“回车”操作——打字机的滑架(Carriage)需要手动推回行首。
  • ASCII码0x0D(十六进制),或\r(转义字符表示)。

换行(LF, \n):

  • 作用:将光标移动到下一行的同一列位置(垂直向下移动一行),但不改变水平位置。
  • 历史来源:打字机的“换行”操作——滚筒旋转一行。
  • ASCII码0x0A(十六进制),或\n(转义字符表示)。
printf(“hello world!\n”);

这里的\n把回车换行的动作都做了,因为C语言会根据当前操作系统自动处理 \n,无需手动写 \r\n(Windows)或 \n(Unix)。

2.行缓冲区

下面的这段代码执行会有什么现象?

#include <stdio.h>
#include <unistd.h>int main()
{printf("hello world!\n");sleep(2);return 0;
}

答案是,这里显示器打印出hello world!,然后再sleep两秒钟程序结束。

那么要是把\n去掉,代码执行会有什么现象?

#include <stdio.h>
#include <unistd.h>int main()
{printf("hello world!");sleep(2);return 0;
}

我们执行后发现,刚开始程序不显示,过了两秒之后,程序快结束时,hello world!打印出来。

那为什么有\n显示器打印是立即显示呢?而没有\n程序是过了两秒再打印呢?sleep在printf之前执行??

我们要知道,C语言执行代码时,一直是从上向下执行的,所有一定是先执行printf,再执行sleep。但为什么打印的内容也是在休眠2秒之后才显示呢?这期间已执行完的内容在哪?——缓存区!!

缓冲区是给显示器提供的,所以只要有缓冲区就必然存在一个刷新策略!

显示器的刷新策略:行刷新!所以有\n,立即显示;没有\n,整个程序结束,然后显示。

如果我们就是想让这个不带\n的程序立即刷新怎么办?

C提供了对应的fflush策略,可以直接强制刷新。

在这里插入图片描述
在这里插入图片描述

stdin对应键盘

stdout,stderror对于显示器

printf打印,是把信息写在stdout(标准输出)里面,所以打印时信息没有刷出来,就用fflush刷新一下标准输出,就可以把这个字符串立即刷新出来。

#include <stdio.h>
#include <unistd.h>int main()
{printf("hello world!");fflush(stdout);sleep(2);return 0;
}

3.demo——倒计时程序

字符输入到显示器上什么位置由谁决定?

是由光标决定。

如果我们的光标在第一个位置,写入9,这时光标会向后移动,但我们想办法让光标再移动到开头,再向里面写8,…,按照这样的原理,我们就可以很容易的实现一个倒计时程序。

#include <stdio.h>
#include <unistd.h>int main()
{int cnt=9;while(cnt>=0){printf("%d\n",cnt);cnt--;sleep(1);}return 0;
}

在这里插入图片描述

这虽然是个倒计时,但并不是我们想要的那种。

今天我们了解了回车,那就可以修改一下我们的代码。

#include <stdio.h>
#include <unistd.h>int main()
{int cnt=9;while(cnt>=0){printf("%d\r",cnt);cnt--;sleep(1);}return 0;
}

我们执行后发现,它竟然什么都不打印了!?

哦哦!!原来是因为把\n变成\r后,没有\n了,所以数字会被写在缓存区里,一直不被更新。

那我们刷新一下吧。

#include <stdio.h>
#include <unistd.h>int main()
{int cnt=9;while(cnt>=0){printf("%d\r",cnt);fflush(stdout);cnt--;sleep(1);}return 0;
}

执行后发现一切正常。?

那0为什么被覆盖掉了?

原来当我们程序退出时,命令行也要打命令行字符串,所以就会把0覆盖掉。

所以我们最后再加一个打印换行符,不然0就会被覆盖掉。

#include <stdio.h>
#include <unistd.h>int main()
{int cnt=9;while(cnt>=0){printf("%d\r",cnt);fflush(stdout);cnt--;sleep(1);}printf("\n");return 0;
}

此时就很完美了。

如果我们要是从10开始倒计时呢?修改后发现为什么只有个位数变化呢?!?

在这里插入图片描述
在这里插入图片描述

其实显示器只认字符,显示器是字符设备。

我们在显示器上打的10,其实不是十,而是1和0两个字符。

我们再修改一下,指定输出十进制整数,宽度至少2个字符,不足补空格。不过%2d默认是左对齐补位(空格填充在数值的左侧),我们想要右对齐,可使用%-2d。

#include <stdio.h>
#include <unistd.h>int main()
{int cnt=10;while(cnt>=0){printf("%-2d\r",cnt);fflush(stdout);cnt--;sleep(1);}printf("\n");return 0;
}

这样就可以了。

4.进度条

我们想写一个进度条不断的推进,旁边有一个百分比不断在增长,和一个不断在旋转的光标。

process.c

#include "process.h"
#include<string.h>
#include<unistd.h>#define SIZE 101
#define STYLE '#'//v2:根据进度,动态刷新一次进度条
void FlushProcess(const char *tips,double total,double current)
{const char *lable = "|/-\\";int len = strlen(lable);static int index =0;char buffer[SIZE];memset(buffer,0,sizeof(buffer));double rate = current*100.0/total;int num=(int)rate;int i = 0;for(;i < num;i++)buffer[i]=STYLE;printf("%s...[%-100s][%.1lf%%][%c]\r",tips,buffer,rate,lable[index++]);fflush(stdout);index %= len;if(num >= 100)printf("\n"); 
}//v1:展示进度条基本功能
void process()
{int rate=0;char buffer[SIZE];memset(buffer,0,sizeof(buffer));const char *lable="|/-\\";int len = strlen(lable);while(rate <= 100){printf("[%-100s][%d%%][%c]\r",buffer,rate,lable[rate%len]);fflush(stdout);buffer[rate] = STYLE;rate++;usleep(10000);}printf("\n");
}                                                                                          

process.h

#pragma once#include <stdio.h>//v1
void process();//v2
void FlushProcess(const char* ,double total,double current); 

main.c

#include "process.h"
#include <unistd.h>
#include <time.h>
#include<stdlib.h>//函数指针类型
typedef void (*call_t)(const char*,double,double);double total = 1024.0;
//double speed[]=1.0;
double speed[]={1.0,0.5,0.3,0.2,0.1,0.01};void download(int total,call_t cb)
{srand(time(NULL));double current=0.0;while(current <= total){cb("下载中",total,current);//进行回调if(current >= total) break;//下载代码int random = rand() % 6;usleep(5000);current += speed[random];if(current>=total) current=total;}
}void upload(int total,call_t cb)
{srand(time(NULL));double current=0.0;while(current <= total){cb("上传中",total,current);//进行回调if(current >= total) break;//下载代码int random = rand() % 6;                                                              usleep(5000);current += speed[random];if(current>=total) current=total;}
}int main()
{                                                                                       download(1024.0,FlushProcess);printf("download 1024.0 MB done\n");download(512.0,FlushProcess);printf("download 512.0 MB done\n");download(256.0,FlushProcess);printf("download 256.0 MB done\n");download(128.0,FlushProcess);printf("download 128.0 MB done\n");download(64.0,FlushProcess);printf("download 64.0 MB done\n");upload(500.0,FlushProcess);return 0;
}

Makefile

BIN=process
#SRC=$(shell ls *.c)
SRC=$(wildcard *.c)
OBJ=$(SRC:.c=.o)
CC=gcc
RM=rm -f$(BIN):$(OBJ)@$(CC) $^ -o $@@echo "链接 $^ 成 $@"
%.o:%.c@$(CC) -c $< #-g@echo "编译 ... $< 成 $@".PHONY:clean
clean:@$(RM) $(OBJ) $(BIN).PHONY:test
test:@echo $(BIN)@echo $(SRC)@echo $(OBJ)

在这里插入图片描述

在这里插入图片描述

相关文章:

  • UIjavaScritIU
  • 模拟投资大师思维:AI对冲基金开源项目详解
  • 从零搭建微服务项目Pro(第6-2章——微服务鉴权模块SpringSecurity+JWT)
  • React-memo (useMemo, useCallback)
  • javassist
  • windows下用xmake交叉编译鸿蒙.so库
  • 【Easylive】Interact与Web服务调用实例及网关安全拦截机制解析
  • 新能源汽车动力电池热管理方案全解析:开启电车续航与安全的密码
  • eSTK.me
  • 【ELF2学习板】利用OpenMP采用多核并行技术提升FFTW的性能
  • 图像预处理-图像边缘检测(流程)
  • 力扣算法ing(60 / 100)
  • 代谢组数据分析(二十四):基于tidymass包从质谱原始数据到代谢物注释结果的实践指南
  • 精益数据分析(5/126):解锁创业成功的关键密码
  • 运算符重载
  • LeetCode(Hot.2)—— 49.字符异位词分组题解
  • 【win 1】win 右键菜单添加 idea pycharm vscode trae 打开文件夹
  • 笔试专题(十一)
  • 什么编程语言市场竞争小,但还易学?
  • Docker应用端口查看器docker-port-viewer
  • 特朗普就防卫负担施压日本,石破茂:防卫费应由我们自主决定
  • 中物联声明:反对美对华物流、海事和造船领域301调查措施
  • 精细喂养、富养宠物,宠物经济掀起新浪潮|私家周历
  • 三一重工去年净利增逾三成至59.75亿,拟分红超30亿元
  • 关于沪泰创新合作,泰州市委书记姜冬冬谈到了三个“合”
  • 别把癌症当鼻炎,爱吃这类食物的人,尤其要警惕