Linux---(七)Makefile写进度条(三个版本)

文章目录

一、前提引入

🎗️下面的代码什么现象?

🎗️现象:马上打印出Hello Makefile!

🎗️下面的代码什么现象?

🎗️现象:停留三秒后打印出Hello Makefile!

现象是先sleep!但是一定是printf先执行,printf早就执行了,只不过字符串没有被显示出来罢了。所以在sleep期间,字符串在哪里?

答案:在输出缓冲区。

二、缓冲区

🎗️C/C++语言,会针对标准输出,给我们提供默认的缓冲区。

🎗️输出缓冲区在哪里呢?

在标准输出流。C/C++默认会打开三个文件流:标准输入流、标准输出流、标准错误流。

🎗️fflush(stdout) 刷新缓冲区

🎗️\n 是一种刷新的策略 行刷新

C程序是默认有输出缓冲区的,数据输出时会默认放在输出缓冲区。之所以可以立马见到数据,是因为该数据被刷新了;如果没有立马见到它,该数据没有被刷新,被暂存在输出缓冲区stdout当中。强制刷新fflsh(stdout)可使数据立马显示出来。

三、回车换行

🎗️注意

回车换行是两个动作

回车是让光标回到该行的最开始位置

换行是换到下一行

🎗️图解

🎗️老式回车键造型(意思是充当两个动作)

🎗️\r 和 \n

🎗️在C语言中,\r代表回车,\n代表换行

🎗️在Linux中,\r代表回车,\n代表回车和换行

🎗️倒计时代码

代码1


效果

形成一个9到1的倒计时效果(打印完一个数字,回车回到最开始打印,下一个数字覆盖上一个数字的打印结果)

注意:如果没有刷新缓冲区那句代码,那么什么也不会显示出来。

代码2

🎗️效果

形成一个从100的倒计时

🎗️注意点

控制两位字符的输出宽度,可达到10的倒计时效果;控制三位字符的输出宽度,可达到100的倒计时效果。控制几位字符就在%d的d前面加数字。

输出结果如果不设置对齐方式,可能会出现覆盖从而达不到预想效果。输出结果左对齐,在%后加上-

思考

🎗️我们向显示器打印的数字真的是数字吗?

答案:不是

往显示器输出123,实际上输出的是1字符,2字符,3字符。

显示器只能显示字符。

因此显示器叫做显示器字符设备。

🎗️我们从键盘上读取到的内容,是什么呢?

b比如说我们从键盘输入1234,键盘读取到的并不是一千两百三十四,而是1字符、2字符、3字符、4字符,然后由scanf将字符串转成整数,放到对应的变量里,这样才有了整数。

四、进度条

预想的进度条效果

构想代码结构

(一)简单原理版本

Makefile

c 复制代码
process:process.c main.c
	gcc -o $@ $^
.PHONY:clean
clean:
	rm -f $@

process.c

c 复制代码
#include "process.h"
#include<string.h>
#include<unistd.h>

#define SIZE 101
#define MAX_RATE 100
#define STYLE '#'
#define STIME 1000*40

const char *str="|/-\\";

void process(){
    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");
}

process.h

c 复制代码
#pragma once 

#include<stdio.h>
void process();

main.c

c 复制代码
#include "process.h"

int main(){
    process();
    return 0;
}

重点代码解读

进度条效果


(二)实际工程实践版本

下载逻辑

Makefile

c 复制代码
process:process.c main.c
	gcc -o $@ $^
.PHONY:clean
clean:
	rm -rf process

process.c

c 复制代码
#include "process.h"
#include<string.h>
#include<unistd.h>

const char *str="|/-\\";

void process_v2(int rate){
    static 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

c 复制代码
#pragma once 

#include<stdio.h>
#include<string.h>
#include<unistd.h>

#define SIZE 101
#define MAX_RATE 100
#define STYLE '#'
#define STIME 1000*40

void process_v2(int);

main.c

c 复制代码
#include "process.h"

#define TARGET_SIZE 1024*1024
#define DSIZE 1024*10

void download(){
    int target=TARGET_SIZE;
    int total=0;

    while(total<target){
        usleep(STIME);
        total+=DSIZE;
        process_v2(total*100/target);
    }
    printf("\n");
}

//下载的软件
int main(){
    download();
    return 0;
}

重点代码解读


改进

process.h

c 复制代码
#pragma once 

#include<stdio.h>
#include<string.h>
#include<unistd.h>

#define SIZE 101
#define MAX_RATE 100
#define STYLE '#'
#define STIME 1000*40

typedef void(*callback_t)(int);
void process_v2(int);

main.c

c 复制代码
#include "process.h"

#define TARGET_SIZE 1024*1024
#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;
}

🎗️回调:把一段可执行的代码像参数传递给其他代码,而这段代码会在某个时刻被调用执行,这就叫做回调。

🎗️改进的版本:

这里,将更新显示的进度条的函数process_v2作为参数传递给download函数,在download函数中需要它时就调用它,调用以函数指针的形式来实现回调函数。

总结

版本2进度条不是在进度条函数内部进行循环打印的,这样有点不好,所以我们采用回调的方式,来进行某种任务的通知,动态更新进度条!(在下载任务中调用进度条)

(三)简单的美化风格

Makefile

c 复制代码
process:process.c main.c
	gcc -o $@ $^
.PHONY:clean
clean:
	rm -rf process

process.c

c 复制代码
#include "process.h"
#include<string.h>
#include<unistd.h>

const char *str="|/-\\";

void process_v3(double rate){
    static char bar[SIZE]={0};
    int num=strlen(str);
    if(rate<=MAX_RATE&&rate>=0){
        printf("[%-100s][%.1f%%][%c]\r",bar,rate,str[(int)rate%num]);
        fflush(stdout);
        if(rate<MAX_RATE){
            bar[(int)rate]=STYLE_BODY;
            bar[(int)rate+1]=STYLE_HEAD;
        }else{
            bar[(int)rate]=STYLE_BODY;
        }
    }
}

process.h

c 复制代码
#pragma once 

#include<stdio.h>
#include<string.h>
#include<unistd.h>

#define SIZE 101
#define MAX_RATE 100
#define STYLE '#'
#define STIME 1000*40
#define STYLE_BODY '='
#define STYLE_HEAD '>'

typedef void(*callback_t)(double);
void process_v3(double);

main.c

c 复制代码
#pragma once 

#include<stdio.h>
#include<string.h>
#include<unistd.h>

#define SIZE 101
#define MAX_RATE 100
#define STYLE '#'
#define STIME 1000*40
#define STYLE_BODY '='
#define STYLE_HEAD '>'

typedef void(*callback_t)(double);
void process_v3(double);

进度条效果


模拟加载中效果

版本3基础上,模拟实现进度条加载过程中不移动时,数字不改变时,(即现实中加载的资源不足以1%时),后面的光标一直旋转(显示加载中)的效果。

🎗️在process.c和main.c文件中做了修改

process.c
c 复制代码
#include "process.h"
#include<string.h>
#include<unistd.h>

const char *str="|/-\\";

void process_v3(double rate){
    static char bar[SIZE]={0};
    int num=strlen(str);
    static int cnt=0;

    if(rate<=MAX_RATE&&rate>=0){
        cnt++;
        cnt=(cnt>=num?0:cnt);
        printf("[%-100s][%.1f%%][%c]\r",bar,rate,str[cnt]);
        fflush(stdout);
        if(rate<MAX_RATE){
            bar[(int)rate]=STYLE_BODY;
            bar[(int)rate+1]=STYLE_HEAD;
        }else{
            bar[(int)rate]=STYLE_BODY;
        }
    }
}
process.h
c 复制代码
#pragma once 

#include<stdio.h>
#include<string.h>
#include<unistd.h>

#define SIZE 101
#define MAX_RATE 100
#define STYLE '#'
#define STIME 1000*40
#define STYLE_BODY '='
#define STYLE_HEAD '>'

typedef void(*callback_t)(double);
void process_v3(double);
main.c
c 复制代码
#include "process.h"

#define TARGET_SIZE 1024*1024
#define DSIZE 1024*10

void download(callback_t cb){
    int testcnt=100;
    int target=TARGET_SIZE;
    int total=0;

    while(total<target){
        usleep(STIME);
        total+=DSIZE;
        double rate=total*100/target;
        if(rate>50.0&&testcnt){
            total=target/2;
            testcnt--;    
         }
    cb(rate);
    }
    cb(MAX_RATE);
    printf("\n");
}

//下载的软件
int main(){
    download(process_v3);
    return 0;
}
Makefile
c 复制代码
process:process.c main.c
	gcc -o $@ $^
.PHONY:clean
clean:
	rm -rf process
重点代码解读


进度条效果

C语言扩展--给进度条带上颜色

C语言有具体的语法可以设置不同的颜色,具体内容大家可以自行搜索,为进度条设置自己喜爱的颜色。



本篇内容的学习就到这里啦!如果对友友们有帮助的话,可以关注后续的创作内容哦~👻

相关推荐
NE_STOP11 分钟前
SpringBoot--简单入门
java·spring
hqxstudying38 分钟前
Java创建型模式---原型模式
java·开发语言·设计模式·代码规范
Dcs1 小时前
VSCode等多款主流 IDE 爆出安全漏洞!插件“伪装认证”可执行恶意命令!
java
保持学习ing1 小时前
day1--项目搭建and内容管理模块
java·数据库·后端·docker·虚拟机
c30%001 小时前
内网渗透——红日靶场五
运维·服务器
京东云开发者1 小时前
Java的SPI机制详解
java
超级小忍2 小时前
服务端向客户端主动推送数据的几种方法(Spring Boot 环境)
java·spring boot·后端
程序无bug2 小时前
Spring IoC注解式开发无敌详细(细节丰富)
java·后端
小莫分享2 小时前
Java Lombok 入门
java
程序无bug2 小时前
Spring 对于事务上的应用的详细说明
java·后端