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

news2024/12/24 2:08:00

文章目录

  • 一、前提引入
    • 🎗️下面的代码什么现象?
    • 🎗️下面的代码什么现象?
  • 二、缓冲区
  • 三、回车换行
    • 🎗️注意
    • 🎗️图解
    • 🎗️老式回车键造型(意思是充当两个动作)
    • 🎗️\r 和 \n
    • 🎗️倒计时代码
      • 代码1
      • 代码2
      • 思考
  • 四、进度条
    • 预想的进度条效果
    • 构想代码结构
    • (一)简单原理版本
      • Makefile
      • process.c
      • process.h
      • main.c
      • 重点代码解读
      • 进度条效果
    • (二)实际工程实践版本
      • 下载逻辑
      • Makefile
      • process.c
      • process.h
      • main.c
      • 重点代码解读
      • 改进
      • process.h
      • main.c
      • 总结
    • (三)简单的美化风格
      • Makefile
      • process.c
      • process.h
      • main.c
      • 进度条效果
      • 模拟加载中效果
        • process.c
        • process.h
        • main.c
        • Makefile
        • 重点代码解读
        • 进度条效果
      • C语言扩展--给进度条带上颜色

在这里插入图片描述

一、前提引入

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

在这里插入图片描述
🎗️现象:马上打印出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

process:process.c main.c
	gcc -o $@ $^
.PHONY:clean
clean:
	rm -f $@

process.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

#pragma once 

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

main.c

#include "process.h"

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

重点代码解读

在这里插入图片描述

进度条效果

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

(二)实际工程实践版本

下载逻辑

在这里插入图片描述

Makefile

process:process.c main.c
	gcc -o $@ $^
.PHONY:clean
clean:
	rm -rf process

process.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

#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

#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

#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

#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

process:process.c main.c
	gcc -o $@ $^
.PHONY:clean
clean:
	rm -rf process

process.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

#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

#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
#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
#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
#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
process:process.c main.c
	gcc -o $@ $^
.PHONY:clean
clean:
	rm -rf process
重点代码解读

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

进度条效果

在这里插入图片描述

在这里插入图片描述

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

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

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


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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1220404.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

一张图厘清各大操作系统的发展脉络

Unix&#xff1a;Unix是一种多用户、多任务、支持多种处理器架构的操作系统。它最初由贝尔实验室的Ken Thompson和Dennis Ritchie在20世纪70年代初开发&#xff0c;是第一个广泛使用的通用操作系统。Unix具有可移植性和可扩展性&#xff0c;因此被广泛应用于服务器、工作站和超…

轻松搭建短域名短链接服务系统,可选权限认证,并自动生成证书认证把nginx的http访问转换为https加密访问,完整步骤和代码

轻松搭建短域名短链接服务系统&#xff0c;可选权限认证&#xff0c;并自动生成证书认证把nginx的http访问转换为https加密访问&#xff0c;完整步骤和代码。 在互联网信息爆炸的时代&#xff0c;网址复杂而冗长&#xff0c;很难在口头告知他人&#xff0c;也难以分享到社交媒体…

学人工智能等于失业?

随着科技的快速发展&#xff0c;人工智能已经渗透到我们生活的方方面面&#xff0c;从手机、智能家居到自动驾驶汽车&#xff0c;都离不开人工智能技术的支持。 因此&#xff0c;学习人工智能已经成为越来越多人追求高薪职业的选择。在这篇文章中&#xff0c;我们将探讨学习人…

树状图怎么画?推荐这个好用的在线树状图软件!

在日常工作和学习中&#xff0c;我们需要用到各种各样的图表&#xff0c;树状图是其中之一。 树状图是什么&#xff1f; 树状图是一种层次式的图形结构&#xff0c;可以用来展示数据之间的关系&#xff0c;并且可以在一定程度上提高工作和学习的效率。 树状图通常用来表示…

第七部分:Maven(项目管理工具)

目录 Maven简介 7.1&#xff1a;为什么学习Maven&#xff1f; 7.1.1、Maven是一个依赖管理工具 7.1.2&#xff1a;Maven是一个构建工具 7.1.3&#xff1a;结论 7.2&#xff1a;Maven介绍 7.3&#xff1a;Maven的优点 Maven安装和配置 7.4&#xff1a;安装教程及环境配置 …

echarts双轴刻度线y轴刻度线对齐

splitNumber属性主要用于设置坐标轴分割的段数。例如&#xff0c;在类目轴&#xff08;category&#xff09;中&#xff0c;可以通过设置splitNumber属性来控制坐标轴被分割成的段数。需要注意的是&#xff0c;这个分割段数只是一个预估值&#xff0c;最终实际显示的段数会在这…

采访仁川市政府:探索《仁川登陆行动》体验及其 NFT 作品集背后的故事!

请简单介绍一下自己 大家好&#xff0c;我是仁川市政府品牌经理崔俊浩&#xff0c;负责《仁川登陆行动》的元宇宙活动。很高兴见到您。 是什么启发了你创作《仁川登陆行动》体验&#xff1f; 《仁川登陆行动》并未得到广泛认可&#xff0c;并且被认为是一项几乎不可能完成的任务…

世界坐标系,相机坐标系,像素坐标系转换 详细说明(附代码)

几个坐标系介绍,相机内外参的回顾参考此文。 本文主要说明如何在几个坐标系之间转换。 本文涉及: 使用相机内参 在 像素坐标系 和 相机坐标系 之间转换。使用相机外参(位姿)在相机坐标系 和 世界坐标系 之间转换。(qw,qx,qy,qz,tx,ty,tz)形式的外参如何使用。以具体情景为…

《高效能人士的七个习惯》思维导图

2006年诺贝尔和平奖得主穆罕默德尤努斯说&#xff0c;《高效能人士的七个习惯》让世人明白一个真理&#xff1a;我们的思维方式会改变生活。如果我们觉得自己穷&#xff0c;就会真的穷。柯维博士教给我们&#xff1a;改变生活的关键是改变思维方式——我们每个人都有无穷的潜力…

期刊会议的选择

目录 找到所有⽬标期刊定具体期刊 找到所有⽬标期刊 定具体期刊

锂离子电池充电的系统抖动问题解决方案

前言 在设计锂离子电池充电器时&#xff0c;会因为充电电流波动导致电压波动&#xff0c;系统异常。 所以分析了锂离子电池的特性&#xff0c;给出了几种解决方法。 有纰漏请指出&#xff0c;转载请说明。 学习交流请发邮件 1280253714qq.com 理论 锂电池简单地可看做一…

【C++学习手札】模拟实现vector

&#x1f3ac;慕斯主页&#xff1a;修仙—别有洞天 ♈️今日夜电波&#xff1a;くちなしの言葉—みゆな 0:37━━━━━━️&#x1f49f;──────── 5:28 &#x1f504; ◀️ ⏸ ▶️ ☰…

傻瓜式提取网页数据的油猴脚本(JavaScript 代码)

目录 一、脚本适用范围 二、将脚本配置到浏览器 三、脚本用法 四、脚本原理 一、脚本适用范围 脚本适用范围&#xff1a;一次性提取任意网站的布局类似的数据&#xff0c;例如 淘宝的商品价格、微博的热搜标题、必应搜索的图片链接 脚本不适用范围&#xff1a;页面布局不相…

协同办公是什么?如何高效协同办公?读这篇就够了!

协同办公是指在工作中&#xff0c;团队成员通过共享信息、协作完成任务&#xff0c;实现高效的工作方式。它有助于促进团队成员之间的沟通、合作和协调&#xff0c;提升工作效率和质量。以下是一些实现高效协同办公的建议和好用的工具推荐。 首先&#xff0c;建立清晰的沟通渠…

单稳态中间继电器\UEG/A-2H/220V 8A导轨安装 JOSEF约瑟

UEG系列中间继电器 UEG/A-2H2D中间继电器UEG/A-4H4D中间继电器UEG/A-2D中间继电器 UEG/A-2H中间继电器UEG/A-4H中间继电器UEG/A-4D中间继电器 UEG/A-6H中间继电器UEG/A-6D中间继电器UEG/A-8H中间继电器 UEG/A-10D中间继电器UEG/A-10H中间继电器UEG/A-2DPDT中间继电器 UEG/A-4DP…

C#学习相关系列之Linq用法---where和select用法(二)

一、select用法 Linq中的select可以便捷使我们的对List中的每一项进行操作&#xff0c;生成新的列表。 var ttlist.select(p>p10); //select括号内为List中的每一项&#xff0c;p10即为对每一项的操作&#xff0c;即对每项都加10生成新的List 用法实例&#xff1a; 1、la…

[pybind11] debug C++代码

首先要有一个项目&#xff0c;我发布在github上了【传送门】 项目的结构如下&#xff1a; 其中src目录下是C代码&#xff0c;test.py是python测试代码。 然后直接开始演示。 1、把项目下载到本地 git clone --recursive https://github.com/immortalmin/pybind11_debug_eg.g…

【论文解读】GPT Understands, Too

一.论文 1.1 P-tuning 区别于之前的工作&#xff0c;这篇工作认为promote可以在句子中的任意位置起到作用&#xff0c;可以将它们插入上下文或目标中 上图中&#xff0c;左图是不使用任何操作&#xff0c;右图是选择在居首和目标前插入promote的embedding&#xff0c;插入pro…

leetcode刷题日记:168. Excel Sheet Column Title(Excel表列名称)

我不知道你看到这一道题目有什么感觉&#xff0c;我先告诉你我有什么感觉&#xff0c;在此之前我再给你写一组有相同模式的数字。 你先告诉我你有什么感觉&#xff0c;有没有感觉&#xff0c;没有感觉的话&#xff0c;那我们就来更深的了解一下&#xff1a; 我们分析最后一…

Linux中的进程终止(详解)

Linux中的进程终止 1. 进程退出场景2. 进程常见退出方法2.1 _exit函数2.2 exit函数2.3 return退出 1. 进程退出场景 代码运行完毕&#xff0c;结果正确代码运行完毕&#xff0c;结果不正确代码异常终止 2. 进程常见退出方法 正常终止&#xff08;可以通过 echo $? 查看进程…