Linux---(七)Makefile写进度条(三个版本)
文章目录
- 一、前提引入
- 🎗️下面的代码什么现象?
- 🎗️下面的代码什么现象?
- 二、缓冲区
- 三、回车换行
- 🎗️注意
- 🎗️图解
- 🎗️老式回车键造型(意思是充当两个动作)
- 🎗️\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.cgcc -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*40const 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.cgcc -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*40void process_v2(int);
main.c
#include "process.h"#define TARGET_SIZE 1024*1024
#define DSIZE 1024*10void 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*40typedef void(*callback_t)(int);
void process_v2(int);
main.c
#include "process.h"#define TARGET_SIZE 1024*1024
#define DSIZE 1024*10void 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.cgcc -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*10void 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.cgcc -o $@ $^
.PHONY:clean
clean:rm -rf process
重点代码解读
进度条效果
C语言扩展–给进度条带上颜色
C语言有具体的语法可以设置不同的颜色,具体内容大家可以自行搜索,为进度条设置自己喜爱的颜色。
本篇内容的学习就到这里啦!如果对友友们有帮助的话,可以关注后续的创作内容哦~👻
相关文章:

Linux---(七)Makefile写进度条(三个版本)
文章目录 一、前提引入🎗️下面的代码什么现象?🎗️下面的代码什么现象? 二、缓冲区三、回车换行🎗️注意🎗️图解🎗️老式回车键造型(意思是充当两个动作)🎗…...
数据库分页查询
数据库只所以要分页查询,其实是界面显示的需要,不是数据库的需要。 数据库本身查询是很快的。本文章是针对这种情况的。 如果数据库本身查询慢,那是优化查询语句的事情了。不在本文章范围内。 今天遇到了这个问题。 是个老项目。在原有的查询…...

如何选择合适的数据库管理工具?Navicat Or DBeaver
写在前面 在阅读本文之前,糖糖给大家准备了Navicat和DBeaver安装包,在公众号内回复“Navicat”或“DBeaver”或"数据库管理工具"来下载。 引言 对于测试而言,在实际工作中往往会用到数据库,那么选择使用哪种类型的数…...

Opencv!!在树莓派上安装Opencv!
一、更新树莓派系统 sudo apt-get update sudo apt-get upgrade二、安装python-opencv sudo apt-get install libopencv-dev sudo apt-get install python3-opencv三、查看是否安装成功 按以下命令顺序执行: python import cv2 cv2.__version__如果出现版本号&a…...

三菱FX3U小项目—传输带定分级控制
目录 一、项目描述 二、IO口分配 三、项目程序 四、总结 一、项目描述 两条运输带顺序相连,为了避免运送的物料在1号运输线上堆积,所以启动时,1号运输带开始运行,5S后2号运输带自动启动。停机时顺序与启动刚好相反,…...

实例解释遇到前端报错时如何排查问题
前端页面报错: 1、页面报错500,首先我们可以知道是服务端的问题,需要去看下服务端的报错信息: 2、首先我们查看下前端是否给后端传了id: 我们可以看到接口是把ID返回了,就需要再看下p_id是什么情况了。 3、我们再次请…...

微电影分销付费短剧小程序开发
微电影系统分销管理付费软件是一款面向微电影制作公司和影视产业的付费软件,它的出现旨在帮助微电影制作公司和影视产业实现分销管理,提高产业的效率和竞争力。本文将介绍微电影系统分销管理付费软件的背景、特点和开发方法。 一、背景 微电影作…...

时间序列预测中的4大类8种异常值检测方法(从根源上提高预测精度)
一、本文介绍 本文给大家带来的是时间序列预测中异常值检测,在我们的数据当中有一些异常值(Outliers)是指在数据集中与其他数据点显著不同的数据点。它们可能是一些极端值,与数据集中的大多数数据呈现明显的差异。异常值可能由于…...

Android---Gradle 构建问题解析
想必做 Android App 开发的对 Gradle 都不太陌生。因为有 Android Studio 的帮助,Android 工程师使用 Gradle 的门槛不算太高,基本的配置都大同小异。只要在 Android Studio 默认生成的 build.gradle 中稍加修改,就都能满足项目要求。但是&am…...
02-2解析JsonPath
一、jsonpath的安装及使用方式 pip安装 pip install jsonpathjsonpath的使用 obj json.load(open(json文件, r, encodingutf‐8)) ret jsonpath.jsonpath(obj, jsonpath语法)可以参考以下这篇博客进行jsonpath的简单入门JSONPath-简单入门...
Git拉取远程指定分支
git clone 指定分支-CSDN博客 即:git clone -b 分支名称 git地址 这种方法也是可以的。但是其实主分支也是拉取下来了,其他分支也拉取下来了,只不过所需分支也拉取下来并且对应当前工作区的代码。如果真的只拉取指定分支,可以用…...

使用Ant Design Pro开发时的一个快速开发接口请求的技巧
使用Ant Design Pro开发时的一个快速开发接口的技巧 当我们的后端在写好接口以后,我们通过swagger knife4j可以生成一个接口文档,后端启动以后,可以生成一个接口文档,当输入地址 localhost:8101/api/v3/api-docs (这…...

m1 rvm install 3.0.0 Error running ‘__rvm_make -j8‘
在使用M1 在安装cocopods 前时,安装 rvm install 3.0.0遇到 rvm install 3.0.0 Error running __rvm_make -j8 备注: 该图片是借用其他博客图片,因为我的环境解决完没有保留之前错误信息。 解决方法如下: 1. brew uninstall --ignore-depe…...
对产品实现汇率换算服务(将两个CompletableFuture对象整合起来,无论它们是否存在依赖)
需求 有一家商店提供的价格是以欧元(EUR)计价的,但是你希望以美元的方式提供给你的客户。你可以用异步的方式向商店查询指定商品的价格,同时从远程的汇率服务那里查到欧元和美元之间的汇率。当二者都结束时,再将这两个…...

数据库期末考前复习题(单选+多选+判断+解答)
文章目录 #数据库考前复习题一、 选择1.单选题2.多选题 二、判断题三、解答请描述数据库中的三大范式关系型数据库ACID特性 #数据库考前复习题 一、 选择 1.单选题 1.使用limit进行分页查询,其中每页10条数据,查询第5页应该写为? SELECT *…...

Ubuntu22.04源码安装ROS-noetic(ROS1非ROS2),编译运行VINS-MONO
1. Ubuntu22.04源码编译安装ROS-noetic 由于22.04默认安装ROS2,但很多仓库都是基于ROS1的,不想重装系统,参考这两个博客安装了ROS-noetic: 博客1. https://blog.csdn.net/Drknown/article/details/128701624博客2. https://zhua…...

窗口管理工具 Mosaic mac中文版功能特点
MosAIc mac是一种窗口管理工具,可帮助您在计算机屏幕上有效地组织和管理多个应用程序窗口。它提供了一种直观的方式来调整和排列窗口,以最大化工作效率。 MosAIc mac窗口管理软件功能和特点 窗口布局:MosAIc允许您选择不同的窗口布局&#x…...

Sql Prompt 10下载安装图文教程
在操作过程中,请暂时关闭你的防病毒软件,以免其误报导致操作失败。 资源 SQL Prompt 10 https://www.aliyundrive.com/s/QuMWkvE1Sv6 点击链接保存,或者复制本段内容,打开「阿里云盘」APP ,无需下载极速在线查看&…...
VB.net webbrowser 自定义下载接口实现
使用《VB.net webbrowser 如何实现自定义下载 IDownloadManager》中的控件ExtendedWebBrowser(下载控件),并扩展了NewWindow2。 使用ExtendedWebBrowser_1过程中,遇到很多问题,花了几天时间,终于解决了所有…...

Android 启动优化案例-WebView非预期初始化排查
作者:邹阿涛涛涛涛涛涛 去年年底做启动优化时,有个比较好玩的 case 给大家分享下,希望大家能从我的分享里 get 到我在做一些问题排查修复时是怎么看上去又low又土又高效的。 1. 现象 在我们使用 Perfetto 进行app 启动过程性能观测时&#…...

相机Camera日志实例分析之二:相机Camx【专业模式开启直方图拍照】单帧流程日志详解
【关注我,后续持续新增专题博文,谢谢!!!】 上一篇我们讲了: 这一篇我们开始讲: 目录 一、场景操作步骤 二、日志基础关键字分级如下 三、场景日志如下: 一、场景操作步骤 操作步…...

centos 7 部署awstats 网站访问检测
一、基础环境准备(两种安装方式都要做) bash # 安装必要依赖 yum install -y httpd perl mod_perl perl-Time-HiRes perl-DateTime systemctl enable httpd # 设置 Apache 开机自启 systemctl start httpd # 启动 Apache二、安装 AWStats࿰…...

Springcloud:Eureka 高可用集群搭建实战(服务注册与发现的底层原理与避坑指南)
引言:为什么 Eureka 依然是存量系统的核心? 尽管 Nacos 等新注册中心崛起,但金融、电力等保守行业仍有大量系统运行在 Eureka 上。理解其高可用设计与自我保护机制,是保障分布式系统稳定的必修课。本文将手把手带你搭建生产级 Eur…...

让AI看见世界:MCP协议与服务器的工作原理
让AI看见世界:MCP协议与服务器的工作原理 MCP(Model Context Protocol)是一种创新的通信协议,旨在让大型语言模型能够安全、高效地与外部资源进行交互。在AI技术快速发展的今天,MCP正成为连接AI与现实世界的重要桥梁。…...
【JavaSE】绘图与事件入门学习笔记
-Java绘图坐标体系 坐标体系-介绍 坐标原点位于左上角,以像素为单位。 在Java坐标系中,第一个是x坐标,表示当前位置为水平方向,距离坐标原点x个像素;第二个是y坐标,表示当前位置为垂直方向,距离坐标原点y个像素。 坐标体系-像素 …...

深入解析C++中的extern关键字:跨文件共享变量与函数的终极指南
🚀 C extern 关键字深度解析:跨文件编程的终极指南 📅 更新时间:2025年6月5日 🏷️ 标签:C | extern关键字 | 多文件编程 | 链接与声明 | 现代C 文章目录 前言🔥一、extern 是什么?&…...

HashMap中的put方法执行流程(流程图)
1 put操作整体流程 HashMap 的 put 操作是其最核心的功能之一。在 JDK 1.8 及以后版本中,其主要逻辑封装在 putVal 这个内部方法中。整个过程大致如下: 初始判断与哈希计算: 首先,putVal 方法会检查当前的 table(也就…...
#Uniapp篇:chrome调试unapp适配
chrome调试设备----使用Android模拟机开发调试移动端页面 Chrome://inspect/#devices MuMu模拟器Edge浏览器:Android原生APP嵌入的H5页面元素定位 chrome://inspect/#devices uniapp单位适配 根路径下 postcss.config.js 需要装这些插件 “postcss”: “^8.5.…...

[免费]微信小程序问卷调查系统(SpringBoot后端+Vue管理端)【论文+源码+SQL脚本】
大家好,我是java1234_小锋老师,看到一个不错的微信小程序问卷调查系统(SpringBoot后端Vue管理端)【论文源码SQL脚本】,分享下哈。 项目视频演示 【免费】微信小程序问卷调查系统(SpringBoot后端Vue管理端) Java毕业设计_哔哩哔哩_bilibili 项…...

Golang——6、指针和结构体
指针和结构体 1、指针1.1、指针地址和指针类型1.2、指针取值1.3、new和make 2、结构体2.1、type关键字的使用2.2、结构体的定义和初始化2.3、结构体方法和接收者2.4、给任意类型添加方法2.5、结构体的匿名字段2.6、嵌套结构体2.7、嵌套匿名结构体2.8、结构体的继承 3、结构体与…...