文章目录
1. make/Makefile的使用
makefile定义了一系列的规则来指定,哪些文件需要先编译,哪些文件需要后编译,哪些文件需要重新编译,甚至于进行更复杂的功能操作;makefile带来的好处就是——“自动化编译”,一旦写好,只需要一个make命令,整个工程完全自动编译,极大的提高了软件开发的效率。
make是一条命令,makefile是一个文件,两个搭配使用,完成项目自动化构建,make会根据makefile的内容,完成编译/清理工作。
2. make/Makefile原理
使用make mytest或者make可以执行gcc test.c -o mytest
使用make clean可以执行rm -f mytest

makefile默认对最新的可执行程序不重新生成

依赖关系和依赖方法是成对出现的;其中,.PHONYY:XXX中的XXX对应的方法总是要执行的,即只要运行make clean就可以执行clean的命令。
补充知识1:为什么makefile对最新的可执行程序,默认不重新形成?
对于大型软件,如果全部重新编译,会耗费很多资源,只对改变的文件进行编译可以提高编译效率
补充知识2:makefile是怎么知道程序需要被编译的?
通过对比可执行文件的最近修改时间和源文件最近的修改时间
3. make/makefile的相关知识
1)make/makefile会自动根据文件中的依赖关系进行自动推导,帮助我们执行所有的相关方法,需要注意的是,**最后执行的依赖列表和依赖方法要放到第一位,**如图中第一二行,其他的顺序可以随便放。如果中间过程某个文件无法形成,则会推导失败

2) 相 当于依赖关系名称, ^相当于依赖关系名称, 相当于依赖关系名称,@相当于目标文件名称

3)可以定义变量,相当于C语言的宏。第一行中左侧是变量名,右侧是变量内容,等号两边不能带空格;使用变量的方法是$(XXX),XXX就是变量名。如果不想显示命令,可以在前面带个@,这样就不会出现命令了

4. 进度条小程序
在写进度条之前,需要先掌握回车换行概念、缓冲区认识以及模拟倒计时上手。
4.1 回车和换行
回车和换行是两个操作,回车是将光标返回到当前行开头,换行就是光标移动到下一行。C语言中 \n 是 回车+换行, \r 则是回车;如果 \r\n 一起使用,则 \n 只执行换行。

4.2 缓冲区
缓冲区是计算机内存中的一块临时存储区域,用于在数据从一个地方传输到另一个地方时暂存数据。
首先需要明确的是:下面的C程序执行顺序一定是执行第六行再执行第七行,因为程序都是从上都下执行的。
那当系统执行sleep时,printf的字符串为什么没有直接显示出来?它又存到哪里了呢?答案就是缓冲区。简单来说:程序结束时一般会自动冲刷缓冲区,所以在sleep结束之后,缓冲区的内容就会显示在屏幕上,就可以看到字符串了。
那如果不想等待sleep结束,那要怎样办?
1)\n。这个是设计和兼容效率、阅读习惯的原因,因为一次刷新字会过多,一个个刷新不符合阅读习惯
2)缓冲区满了。这时就会释放缓冲区,也会执行刷新
3)强制刷新。调用 fflush() 可以强制进行刷新


4.3 倒计时
原理是执行回车但不执行换行,同时强制刷新缓冲区,并进行sleep,这样光标会处于第一行,数字也会显示出来。
如果倒计时数字是2位或者以上,需要在打印时用%nd,n为位数,这样才能对全部字符(显示器显示的100是显示3个字符,而不是1个数字)进行覆盖


4.4 进度条
在掌握上面的知识后,就可以写一个简单的进度条加载小程序。它是利用了缓冲区强制刷新以及只回车不换行的原理,和倒计时有相似的模样。
1)简单进度条
这里将程序分成4个,makefile负责执行编译程序,Processbar.h包含头文件以及函数接口,Processbar.c则是实现进度条,Main.c相当于启动器。更多说明部分可以参照程序中的注释。
Processbar.h
#pragma once
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#define Length 101 //定义进度条长度
#define Style '#' //定义进度条样式
void ProBar();
Processbar.c
#include "Processbar.h"
void ProBar()
{
char bar[Length];
char* lable = "|/-\\"; //最右侧样式
memset(bar, '\0', sizeof(bar)); //初始化数组
int len = strlen(lable);
int cnt = 0;
while(cnt <= 100)
{
printf("[%-100s], [%3d%%], [%c]\r", bar, cnt, lable[cnt%len]); //打印进度条,进度百分比,最右侧动态变化
fflush(stdout); //强制刷新缓冲区
bar[cnt++] = Style;
usleep(2000); //休眠,以微秒为单位
}
printf("\n");
}
Main.c
#include "Processbar.h"
int main() {
ProBar();
return 0;
}
makefile
#文件已经包含了头文件,而且编译过程中会进行头文件展开
#因此可以不用包含头文件,写上也没有问题
Processbar:Main.c Processbar.c
gcc Main.c -o $@ $^
.PHONY:clean
clean:
rm -f $@
效果:

2)模拟下载场景
接下来模拟下载的场景,主要修改以下三个文件,makefile不变
Processbar.h
#pragma once
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#define Length 101 //定义进度条长度
#define Style '#' //定义进度条样式
void download();
void ProBar(double filesize, double current); //传入文件大小和下载进度
typedef void(*callback_t)(double, double); //回调函数
Processbar.c
这里说明两种方法,第一种是正常的调用,第二种采用回调函数
#include "Processbar.h"
void ProBar()
{
char bar[Length];
char* lable = "|/-\\"; //最右侧样式
memset(bar, '\0', sizeof(bar)); //初始化数组
int len = strlen(lable);
double rate = current*100.0/filesize;
int cnt = 0;
int loop_count = (int)rate;
while(cnt <= loop_count)
{
bar[cnt++] = Style; //采用字符串拼接的方式,同时防止进度条闪烁
}
printf("[%-100s], [%3.1lf%%], [%c]\r", bar, rate, lable[cnt%len]); //打印进度条,进度百分比,最右侧动态变化
fflush(stdout); //强制刷新缓冲区
}
void download(callback_t cb)
{
double filesize = 100*1024*1024*1.0; //模拟文件大小
double current = 0.0; //模拟当前下载大小
double bandwidth = 1024*1024*1.0; //模拟下载带宽
printf("download begin, current: %lf\n", current);
while(current <= filesize)
{
//1、正常的调用方法,传入文件大小和当前下载大小
//ProBar(filesize, current);
//2、用回调函数传入
cb(filesize, current);
current += bandwidth; //模拟下载贷款
usleep(20000);
}
printf("\ndownload done, filesize: %lf\n", filesize);
}
Main.c
#include "Processbar.h"
int main() {
//1、模拟下载
//download();
//2.用回调函数传入
download(ProBar);
return 0;
}
1031

被折叠的 条评论
为什么被折叠?



