【Linux】-- 开发工具yum、vim、gcc、g++、gdb、make、makefile使用介绍(三)

简介: 【Linux】-- 开发工具yum、vim、gcc、g++、gdb、make、makefile使用介绍

五、make/Makefile

1.了解make/Makefile

(1)make

       make是一个解释makefile中指令的命令工具。一个工程中的源文件不计数,其按类型、功能、模块分别放在若干个目录中。

(2)Makefile

       Makefile是Linux项目自动化构建工具,Makefile规定义了一系列的规则来指定,哪些文件需要先编译,哪些文件需要后编译,哪些文件需要重新编译,甚至于进行更复杂的功能操作。编译的安排就叫做构建。构建规则都写在Makefile文件里面,要学会如何Make命令,就必须学会如何编写Makefile文件。makefile带来的好处就是——“自动化编译”,一旦写好,只需要一个make命令,整个工程完全自动编译,极大的提高了软件开发的效率,makefile成为了一种在工程方面的编译方法。

       make是一条命令,makefile是一个文件,两者搭配使用,形成可执行程序,完成项目自动化构建。

2.如何写一个Makefile

与源文件同级,创建一个Makefile文件:

将编译InsertSort.c的命令写入Makefile中。其中,第一行叫做依赖关系,第二行叫做依赖方法:

1. InsertSort:InsertSort.c       #依赖关系
2.         gcc InsertSort.c -o InsertSort -std=c99     #依赖方法

第一行开始的InsertSort叫做目标,InsertSort.c叫做前置条件,gcc InsertSort.c -o InsertSort -std=c99是命令,命令前有Tab键:

执行make命令后,会自动执行Makefile文件中的命令:

但是此时想再make一下,会发现不让make了:

因为可执行文件已经是最新了。Makefile默认的目标是文件,如果目标不是真实存在的文件,而是一个命令呢,那么这个目标就是伪目标,伪目标没有依赖关系,只有依赖方法,如下clean就是一个伪目标,make就不会去检查是否存在一个叫做clean的文件,而是每次运行都执行对应的命令:

1. InsertSort:InsertSort.c
2.         gcc InsertSort.c -o InsertSort -std=c99
3. .PHONY:clean      #伪目标
4. clean:
5. rm -f InsertSort

其中:

由于make扫描Makefile文件时,默认只会形成一个目标依赖关系,一般是第一个,因此,现在执行make,并不能达到删除InsertSort可执行文件的目的,因为make会生成第一个目标也就是生成InsertSort可执行程序:

此时要执行非第一个目标时,需要make加上目标:

当把两个目标的顺序交换一下,会发现,执行make时就先执行clean命令:

这下直接make时,就不是编译生成可执行文件了, 而是执行clean命令,如果要生成可执行程序,必须执行make 加上目标:

也可以用$@表示目标文件,$^表示上一行的冒号后面的依赖文件列表:

六、进度条小程序

1.回车和换行

  • 回车:行不变,列回到当前行的最开始
  • 换行:列不变,行切换到下一行

例如,如下代码,当执行打印后,需要等待3秒才结束程序:

enter.c

1. #include<stdio.h>
2. 
3. int main()
4. {
5. printf("33333333\n");
6. sleep(3);
7. 
8. return 0;
9. }

Makefile

1. enter:enter.c
2.         gcc -o $@ $^
3. .PHONY:clean
4. clean:
5. rm -f enter

那么打印内容会在屏幕上出现3秒以后程序才结束:

如果不加\n,那么一开始就不会打印字符串,等待3秒后,才会打印出字符串:

 

这两个程序运行结果并不代表sleep先于printf执行,其实只是printf已经执行,但是数据没有被立即刷新到显示器上而已。当没有\n时,字符串会暂时保存到用户C语言级别的缓冲区当中,显示器设备的刷新策略就是行刷新(\n),即立即刷新。

如果想在不带\n的情况下,让数据立即刷新出来, 可以调用fflush接口,不过fflush的参数是文件流:

那么对于这个程序,应该给fflush传什么参数呢?

由于在C语言中的文件操作,系统会默认地帮我们把对应的文件以C语言的方式打开,并且会默认打开3个输入输出流:

为什么程序会默认打开着3个输入输出流呢?因为程序为了帮我们计算数据,就有数据源和数据结果,C语言为了避免我们麻烦,默认给我们打开了这3个输入输出流,供我们读写。

对于刚刚的程序,想让代码立即刷新出来,我们借助fflush函数,因为printf是向stdout打印,那么刷新也是向stdout刷新,所以将stdout作为fflush的参数:

再执行make clean;make,会发现先刷新字符串,但是再等了3秒程序才结束:

对于\r,仅回车,行不变,列回到当前行的最开始,由于没有\n,所以每次循环的打印结果不会被显示出来:

1. #include<stdio.h>
2. 
3. int main()
4. {
5. int count  = 5;
6. while(count)
7.         {
8. printf("%d\r",count);
9.                 count--;
10. sleep(1);
11.         }
12. 
13. return 0;
14. }

那么为了让打印结果显示出来,可以使用fflush:

但是结果就变成在这个位置倒计时:

 

假如将count初始化为10,执行结果就更离谱:

这是因为显示器是字符设备,凡是显示到显示器上面的内容都是字符,凡是从键盘读取的内容也都是字符。所以上面第一次打印的count值为10并不是数字10,而是字符'1'和字符'0'。再对count--时,count的值只有一个字符,比如9,所以只能覆盖到一个字符,因此字符'0'永远都不会动。要解决这个问题,可以输出2个字符,这样就会把字符'0'给覆盖了:

执行结果:

 

2. 实现进度条小程序

假如实现进度条小程序,在同一行打印'#',每次刷新就多打印一个'#',以下代码是实现不了的,因为显示器是行刷新,没有\n就刷新不出来进度条:

1. #include<stdio.h>
2. #include<string.h>
3. #include<unistd.h>
4. 
5. #define NUM 100
6. 
7. int main()
8. {
9. char bar[NUM+1];
10. memset(bar,'\0',sizeof(bar));
11. 
12. int i = 0;
13. while(i <= 200)
14.         {
15. printf("%s",bar);//没有\n,在显示器上显示不出来‘#’
16.                 bar[i] = '#';
17.                 i++;
18. sleep(1);
19.         }
20. 
21. return 0;
22. }

那么加了\n以后呢?虽然'#'可以打印出来,但是打印却变成了不在同一行显示'#',这不符合我们的要求:

 

所以考虑到使用fflush:

但是发现运行结果,是每隔1秒自动多打印n个'#':

这不符合我们的需求,我们需要每次增加一个'#'。可以加上\r

现在每次刷新增加一个#":

这下达到了我们的要求,但是有没有发现好像刷新的太慢了,那就把刷新间隔缩短一些:

这下快一些了 :

但是i的上限是200,程序要执行好久才能看到最终的执行结果,而且还刷屏,不好观察,将i的上限改为20:

执行结果发现,执行完毕时提示符[delia@VM-8-17-centos progressBar]$ 和进度条在同一行呢:

能不能把提示符去掉?可以在程序执行结束时,换行:

现在程序执行结束就换行了:

如果想让进度条被[ ]包起来呢?

发现进度条从右向左显示:

加上'-'就从左向右显示了:

执行结果如下:

想加上数字百分比呢?

执行结果如下:

想在结尾增加光标旋转呢?

执行结果如下:

 

假如想更换进度条颜色呢?比如换成绿色:

执行结果如下:

好啦,进度条做好啦。完整代码段:

1. #include<stdio.h>
2. #include<string.h>
3. #include<unistd.h>
4. 
5. #define NUM 100
6. 
7. int main()
8. {
9. char bar[NUM+1];
10. memset(bar,'\0',sizeof(bar));
11. 
12. const char *token = "|/-\\";
13. 
14. int i = 0;
15. while(i <= 100)
16.         {
17. printf("\033[32m[%-100s][%d%%] [%c]\r",bar,i,token[i%4]);
18. fflush(stdout);
19.                 bar[i] = '#';
20.                 i++;
21. usleep(50000);
22.         }
23. 
24. printf("\n");
25. return 0;
26. }
相关实践学习
阿里云图数据库GDB入门与应用
图数据库(Graph Database,简称GDB)是一种支持Property Graph图模型、用于处理高度连接数据查询与存储的实时、可靠的在线数据库服务。它支持Apache TinkerPop Gremlin查询语言,可以帮您快速构建基于高度连接的数据集的应用程序。GDB非常适合社交网络、欺诈检测、推荐引擎、实时图谱、网络/IT运营这类高度互连数据集的场景。 GDB由阿里云自主研发,具备如下优势: 标准图查询语言:支持属性图,高度兼容Gremlin图查询语言。 高度优化的自研引擎:高度优化的自研图计算层和存储层,云盘多副本保障数据超高可靠,支持ACID事务。 服务高可用:支持高可用实例,节点故障迅速转移,保障业务连续性。 易运维:提供备份恢复、自动升级、监控告警、故障切换等丰富的运维功能,大幅降低运维成本。 产品主页:https://www.aliyun.com/product/gdb
相关文章
|
25天前
|
存储 Linux 编译器
vim编辑器和gcc/g++编辑器的使用讲解
vim编辑器和gcc/g++编辑器的使用讲解
47 2
|
1月前
|
NoSQL Linux 开发工具
【Linux】环境基础开发工具的使用之gdb详解(三)
【Linux】环境基础开发工具的使用之gdb详解(三)
|
1月前
|
Linux 编译器 开发工具
【Linux】环境基础开发工具的使用之gcc详解(二)
【Linux】环境基础开发工具的使用之gcc详解(二)
|
11天前
|
Ubuntu Linux 编译器
【Linux】4. 开发工具的使用(yum/vim)
【Linux】4. 开发工具的使用(yum/vim)
42 2
|
NoSQL Linux 编译器
【Linux】——调试器-gdb的使用
【Linux】——调试器-gdb的使用
|
自然语言处理 Linux 编译器
Linux编译器——gcc/g++使用
Linux编译器——gcc/g++使用
|
1月前
|
NoSQL Linux 编译器
『Linux升级路』基础开发工具——gdb篇
『Linux升级路』基础开发工具——gdb篇
|
1月前
|
Linux 开发工具 C语言
『Linux升级路』基础开发工具——gcc/g++篇
『Linux升级路』基础开发工具——gcc/g++篇
|
1月前
|
Linux 开发工具 Windows
『Linux升级路』基础开发工具——yum篇
『Linux升级路』基础开发工具——yum篇
|
1月前
|
Linux 编译器 Shell
Linux嵌入式系统之Linux嵌入式系统之交叉编译中gcc编译器的工作流程
Linux嵌入式系统之Linux嵌入式系统之交叉编译中gcc编译器的工作流程
18 0