上篇文章:Linux:自动化构建-make/Makefile
最终结果预览:

目录
1.区分回车与换行
回车与换行并不是同一个概念。
回车是指回到当前行的开始,换行是指新开一行。
其中,\r指回车,\n或std::endl;或 \r\n 指回车与换行。
2.行缓冲区
下方代码谁先执行?


下方代码谁先执行?

在C语言中,代码都是从上到下执行的,上述代码在sleep期间,printf一定已经执行完了,只不过数据没有被显示出来,那么在sleep期间,hello字符串在哪里呢?
实际是是被缓存起来了,在程序结束时,会自动刷新。
而对于第一段代码,回车换行会立即刷新到显示器中
那么在第二段代码的前提下,要怎么立即刷新?见下:

3.写一个倒计时的程序


4.进度条代码
4.1基石
先创建三个源文件:

再进入到main.c文件中,包含process.h头文件,并再转换到头文件中:

在头文件中声明方法:

.c文件:

编写makefile:
在阅读 Makefile 时,这三个自动化变量最容易混淆:
符号 含义 示例场景 $@目标文件 (Target) 在 main: main.o中,$@就是main$^所有依赖文件 (All Prerequisites) 在 main: a.o b.o中,$^就是a.o b.o$<第一个依赖文件 (First Prerequisite) 在 main.o: main.c中,$<就是main.c

进行一次调试:

4.2版本一

测试:

测试发现,进度条是回车换行每隔一个%就进行一次,并且等待时间较长,优化:
认识usleep(微秒):

代码:

此时运行结果为:

但是它在输出时,右括号是随着=进行移动的,应该将其大小固定,让=进行移动即可,再优化:

但是此时进度条是倒着打印的,并且进度括号大小没有固定且没有%显示:

原因是在C语言的printf中,%Ns(N为正数)会使字符串右对齐,左侧填充空格。
优化:


加入旋转光标:
原理:| / - \依次出现。


另一种显示样式:...


优化:

4.3带入场景
虽然此时的进度条代码初具雏形,但是并没有实际作用。我们进入main.c文件,假设有一个下载任务,完成下方的简易代码:

4.4版本二
4.4.1需求一
完成一个随着下载进度实时更新的动态进度条。
process.c:
1 #include "process.h"
2 #include <string.h>
3 #include <unistd.h>
4
5 #define SIZE 102
6 #define LABLE '='
7
8 // 进度条版本二
9 void Process(double total, double current)
10 {
E> 11 if(current > total)
12 return;
13 // 动态进度条
14 // 1.计算比率
E> 15 double rate = current * 100.0 / total;
16 char out_bar[SIZE];
17 memset(out_bar, '\0', sizeof(out_bar));
18 // 2.填充进度字符
19 int i = 0;
20 for( ; i < (int)rate; i++)
21 {
22 out_bar[i] = LABLE;
23 }
24 // 3.刷新进度条
25 printf("[%-100s][%lf]\r", out_bar, rate);
26 fflush(stdout);
27 }
28
main.c:
1 #include "process.h"
2 #include <unistd.h>
3
4 // 下载
5 double gtotal = 1024.0; // 目标文件的总大小
6 double gspeed = 1.0; // 网络速度
7 void DownLoad(double total)
8 {
9 double current = 0.0; // 当前下载了多少
10 while(current <= total)
11 {
12 usleep(5000); // 模拟下载
13 current += gspeed;
14
15 Process(total, current); // 更新进度条
16 }
17 }
18 int main()
19 {
20 // version1
21 //Process(); // 进度条程序
22
23 DownLoad(gtotal);
24 return 0;
25 }

process.h:
1 #pragma once
2
3 #include <stdio.h>
4
5 void Process(double tatal, double current);
查看此时的效果:

4.4.2优化一
进行优化:


4.4.3需求二
在进度条运行过程中,其下载速度也会与网络环境相关,此时添加旋转光标表示仍进行下载的过程:
9 void Process(double total, double current)
10 {
11 if(current > total)
12 return;
13 // 旋转光标只与process函数有关
14 static const char *lable = "|/-\\";
15 int size = strlen(lable);
16 static int index = 0;
17
18 // 动态进度条
19
20 // 1.计算比率
21 double rate = current * 100.0 / total;
22 char out_bar[SIZE];
23 memset(out_bar, '\0', sizeof(out_bar));
24
25 // 2.填充进度字符
26 int i = 0;
27 for( ; i < (int)rate; i++)
28 {
29 out_bar[i] = LABLE;
30 }
31
32 // 3.刷新进度条
33 printf("[%-100s][%5.1lf%%][%c]\r", out_bar, rate, lable[index]);
34 fflush(stdout);
35 index++;
36 index %= size;
37
38 // 4.刷新进度条完成后,换行
39 if(current >= total)
40 printf("\r\n");
41 }

4.4.4需求三
显示目标内容的容量,当前下载量,网速等数据。
process.c:
1 #include "process.h"
2 #include <string.h>
3 #include <unistd.h>
4
5 #define SIZE 102
6 #define LABLE '='
7
8 // 进度条版本二
9 void Process(double total, double current, double speed, const char *userinfo)
10 {
11 if(current > total)
12 return;
13 // 旋转光标只与process函数有关
14 static const char *lable = "|/-\\";
15 int size = strlen(lable);
16 static int index = 0;
17
18 // 动态进度条
19
20 // 1.计算比率
21 double rate = current * 100.0 / total;
22 char out_bar[SIZE];
23 memset(out_bar, '\0', sizeof(out_bar));
24
25 // 2.填充进度字符
26 int i = 0;
27 for( ; i < (int)rate; i++)
28 {
29 out_bar[i] = LABLE;
30 }
31
32 // 3.刷新进度条
33 printf("[%-100s][%5.1lf%%][%c] | %.1lf / %.1lf, speed: %.1lf%s\r", out_bar, rate, lable[index], total, current, speed, userinfo);
34 fflush(stdout);
35 index++;
36 index %= size;
37
38 // 4.刷新进度条完成后,换行
39 if(current >= total)
40 printf("\r\n");
41 }
main.c:
1 #include "process.h"
2 #include <unistd.h>
3
4 // 下载
5 double gtotal = 1024.0; // 目标文件的总大小
6 double gspeed = 1.0; // 网络速度
7 void DownLoad(double total)
8 {
9 double current = 0.0; // 当前下载了多少
10 while(current <= total)
11 {
12 usleep(5000); // 模拟下载
13 current += gspeed;
14
E> 15 Process(total, current, gspeed, "MB/s"); // 更新进度条
16 }
17 }
18 int main()
19 {
20 // version1
21 //Process(); // 进度条程序
22
23 DownLoad(gtotal);
24 return 0;
25 }
结果:

4.4.5优化二
网速不是固定不变的,给出随机网速并与进度结合。
1 #include "process.h"
2 #include <unistd.h>
E> 3 #include <stdlin.h>
4 #include <time.h>
5
6 // 下载
7 double gtotal = 1024.0; // 目标文件的总大小
8 double gspeed = 1.0; // 网络速度
9 void DownLoad(double total)
10 {
11 double level[] = {0.01, 0.05, 1.0, 0.5, 1.5, 2.5, 5.5, 10.0, 3.6, 20.0, 30.0, 40.0, 50.0 , 68.9, 89.1, 40.9, 30.1};
12 int num = sizeof(level)/sizeof(level[0]);
13
14 double current = 0.0; // 当前下载了多少
15 while(1)
16 {
17 usleep(10000); // 模拟下载
E> 18 double speed = level[rand()%num];
19 current += speed;
20 if(current >= total)
21 {
22 current = total;
23 Process(total, current, speed, "MB/s"); // 更新进度条
24 break;
25 }
26 else
27 {
28 Process(total, current, speed, "MB/s"); // 更新进度条
29 }
30 }
31 }
32 int main()
33 {
34 // version1
35 //Process(); // 进度条程序
36
37 DownLoad(gtotal);
38 return 0;
39 }
4.5代码测试
1 #include "process.h"
2 #include <unistd.h>
3 #include <stdlib.h>
4 #include <time.h>
5
6 // 下载
7 double gtotal = 1024.0; // 目标文件的总大小
8 double gspeed = 1.0; // 网络速度
9 void DownLoad(double total)
10 {
11 double level[] = {0.01, 0.05, 1.0, 0.5, 1.5, 2.5, 5.5, 10.0, 3.6, 20.0, 30.0, 40.0, 50.0 , 68.9, 89.1, 40.9, 30.1};
12 int num = sizeof(level)/sizeof(level[0]);
13
14 double current = 0.0; // 当前下载了多少
15 while(current <= total)
16 {
17 usleep(100000); // 模拟下载
18 double speed = level[rand()%num];
19 current += speed;
20 if(current >= total)
21 {
22 current = total;
23 Process(total, current, speed, "MB/s"); // 更新进度条
24 break;
25 }
26 else
27 {
28 Process(total, current, speed, "MB/s"); // 更新进度条
29 }
30 }
31 }
32 int main()
33 {
34 // version1
35 //Process(); // 进度条程序
36 srand(time(NULL));
37 printf("download: \n");
38 DownLoad(gtotal);
39 printf("download: \n");
40 DownLoad(102.0);
41 printf("download: \n");
42 DownLoad(11.9);
43 printf("download: \n");
44 DownLoad(89.0);
45 printf("download: \n");
46 DownLoad(900.0);
47
48 return 0;
49 }
优化
每一个进度条都是独立的,这里使用回调函数,此外,通过printf函数进行颜色的输出:
process.h:
定义一个返回值为void,名称为flush_t的指针
1 #pragma once
2
3 #include <stdio.h>
4 typedef void (*flush_t)(double total, double current, double speed, const char *userinfo);
5 void Process(double total, double current, double speed, const char *userinfo);
process.c:
1 #include "process.h"
2 #include <string.h>
3 #include <unistd.h>
4 #include <stdio.h>
5
6 #define SIZE 102
7 #define LABLE '='
8
9 // 进度条版本二
10 void Process(double total, double current, double speed, const char *userinfo)
11 {
12 if(current > total)
13 return;
14 // 旋转光标只与process函数有关
15 static const char *lable = "|/-\\";
16 int size = strlen(lable);
17 static int index = 0;
18
19 // 动态进度条
20
21 // 1.计算比率
22 double rate = current * 100.0 / total;
23 char out_bar[SIZE];
24 memset(out_bar, '\0', sizeof(out_bar));
25
26 // 2.填充进度字符
27 int i = 0;
28 for( ; i < (int)rate; i++)
29 {
30 out_bar[i] = LABLE;
31 }
32
33 // 3.刷新进度条
34 // \033[1;32m 绿色 (进度条)
35 // \033[1;33m 黄色 (百分比)
36 // \033[1;34m 蓝色 (速度)
37 // \033[0m 重置颜色
38 printf("[\033[1;32m%-100s\033[0m][\033[1;33m%5.1lf%%\033[0m][%c] | %.1lf / %.1lf, speed: \033[1;34m%.1lf%s\033[0m\r",
39 out_bar, rate, lable[index], total, current, speed, userinfo);
40 //printf("[%-100s][%5.1lf%%][%c] | %.1lf / %.1lf, speed: %.1lf%s\r", out_bar, rate, lable[index], total, current, speed, userinfo);
41 fflush(stdout);
42 index++;
43 index %= size;
44
45 // 4.刷新进度条完成后,换行
46 if(current >= total)
47 printf("\r\n");
48 }
49
main.c:
1 #include "process.h"
2 #include <unistd.h>
3 #include <stdlib.h>
4 #include <time.h>
5
6 // 回调函数
7 double gtotal = 1024.0; // 目标文件的总大小
8 double gspeed = 1.0; // 网络速度
9 void DownLoad(double total, flush_t cb)
10 {
11 double level[] = {0.01, 0.05, 1.0, 0.5, 1.5, 2.5, 5.5, 10.0, 3.6, 20.0, 30.0, 40.0, 50.0 , 68.9, 89.1, 40.9, 30.1};
12 int num = sizeof(level)/sizeof(level[0]);
13
14 double current = 0.0; // 当前下载了多少
15 while(1)
16 {
17 usleep(100000); // 模拟下载
18 double speed = level[rand()%num];
19 current += speed;
20 if(current >= total)
21 {
22 current = total;
23 cb(total, current, speed, "MB/s"); // 更新进度条
24 break;
25 }
26 else
27 {
28 cb(total, current, speed, "MB/s"); // 更新进度条
29 }
30 }
31 }
32 int main()
33 {
34 // version1
35 //Process(); // 进度条程序
36 srand(time(NULL));
37 printf("download: \n");
38 DownLoad(gtotal, Process);
39 printf("download: \n");
40 DownLoad(102.0, Process);
41 printf("download: \n");
42 DownLoad(11.9, Process);
43 printf("download: \n");
44 DownLoad(89.0, Process);
45 printf("download: \n");
46 DownLoad(900.0, Process);
47
48 return 0;
49 }
显示结果:

本章完。