一:库的理解
库的含义:库是一套方法或者数据库,为我们开发提供最基本的保证(基本接口,功能),加速我们二次开发。
1.动态库和动态链接
在Linux中,以.so结尾的文件称为动态库。假设我们自己的程序在运行时需要调用库中的方法,程序运行到需要调用库中方法时代码会在库中找到该方法,并跳转到该方法中执行该段代码完之后返回才执行后序代码的链接方式称为动态链接。
2.静态库和静态链接
在Linux中,以.a结尾的文件称为静态库。 在程序编译时,将所有需要的库函数的代码直接复制到可执行文件中的链接方式称为静态链接。
特点 | 静态链接 | 动态链接 |
文件大小 | 较大(包含所有库代码) | 较小 |
内存占用 | 每个程序独立占用内存(冗余) | 多个程序共享同一库的内存映射 |
编译速度 | 较慢(需复制库代码) | 较快 |
二:make和makefile
1.含义:
make是一个命令
makefile是一个文件,m既可以大写也可以小写,即可以写成makefile也可以写成Makefile。
2.makefile的基本概念
2.1.依赖关系和依赖方法
第一行表明目标文件:生成目标文件依赖的源文件 ,如在下面例子中就表明
第二行,以tab键开头,接着表明想要生成目标文件需要执行的命令,如在下面例子中用gcc方法将code.c文件生成指定目标文件code
其中依赖的文件可以不止一个,可以有多个。接着我们在终端输入make命令时就会在当前目录下查找Makefile/makefile文件,接着就会按照makefile/Makefile文件中的内容使用gcc方法依赖code.c文件生成目标文件code。
如下图所示:
如下图所示,在依赖方法前面加上@符号表示不回显该条命令。如下图当我们在第8行这个依赖方法前面加上@符号,执行make命令的时候就不会打印出任何命令,而clean的依赖方法由于没有加上@符号,所以正常打印命令rm -f myproc。
可以存在多行依赖方法
如上图所示:myproc和clean的依赖方法都有两行 第一组依赖方法为@$(CC) $(FLAGS) $@ $^ 和 @echo "linking $^ to $@",由于前面加了@符号,所以第一个依赖方法不回显,只打印了第二行依赖方法,下组类似;结果如下图:
例子2:
在上图中,根据上面所讲的知识我们可以知道第一行和第二行 myproc:myproc.c gcc -o myproc myproc.c就是一组依赖关系和依赖方法。第三行 .PHONY 修饰的clean称为伪目标;而第四行和第五行也是一组依赖关系和依赖方法,其中clean依赖的源文件可以是空
如上图所示:当我们执行make命令时就会自动执行Makefile文件中的依赖方法命令,即
gcc -o myproc myproc.c生成目标文件myproc,当我们想要删除这个目标文件时就可以执行
make clean这个命令(clean依赖方法rm -f myproc就是删除myproc这个目标文件)。在这里我们不妨想一下为什么执行第一组依赖关系和依赖方法的时候直接使用make命令就可以了呢,而我们想要执行第二组依赖关系和依赖方法的时候就需要执行make clean命令呢?
交换第一组依赖关系和依赖方法和第二组依赖关系和依赖方法位置
如上图所示,当我们执行make命令时可以看到执行的依赖方法不再是gcc -o myproc myproc.c生成目标文件myproc,而是执行依赖方法rm -f myproc就是删除myproc这个目标文件。而当我们执行make myproc命令时才执行gcc -o myproc myproc.c生成目标文件myproc。由此可见,make命令扫描Makefile文件时,默认从上往下扫描,默认执行第一个依赖方法,所以我们一般写Makefile文件时将需要生成的目标文件的依赖关系和依赖方法放在前面。
2.2. .PHONY符号声明
我们将被.PHONY修饰的称为伪目标,作用就是伪目标的依赖关系和依赖方法总是被执行。
如下图所示,Makefile文件中有两组依赖关系和依赖方法,其中myproc的依赖关系和依赖方法没有被.PHONY修饰声明,clean则被.PHONY修饰声明。因此,myproc总是不被执行,clean总是被执行,那么什么是总是不被执行呢?
如下图所示:我们一个执行了四次make命令,其中只有第一个make命令成功执行了对应的依赖方法,其他的则报错 make: 'myproc' is up to date. ,这是因为myproc文件没有被重新编译过,所以没有重新生成目标文件的必要;而当我们将myproc这组依赖关系和依赖方法也用.PHONY修饰声明时,我们发现make命令就可以一直被执行而不报错了。因此我们则称被.PHONY修饰的伪目标的依赖关系和依赖方法总是被执行;而默认老代码不做重新编译。
2.3. 基于常变量版的Makefile
如上图所示:1~5行的内容都是相当于对变量的宏定义,将myproc定义为BIN,将gcc定义为CC,将myproc.c定义为SRC,将 -o 定义为FLAGS,将rm -f 定义为RM;其中的:=也可以直接写成=。而接下来的7~11行就相当于我们前面所提及的两组依赖关系和依赖方法,其中$(BIN)的意思为将引用变量BIN,接下来的$(SRC)等也类似,因此最终命令将变为 myproc:myproc.c
gcc -o myproc myproc.c 和 rm -f myproc。接下来我们又定义了一组依赖关系和依赖方法,而其中@echo $(BIN)的意思是将变量BIN的内容打印出来并且不回显该条命令,即myproc;以下皆类型。make test一下这个文件结果如下如:
2.4. 特殊字符@和^
如上图所示,当我们在写myproc这个目标文件的依赖方法的时候,其中的目标文件和依赖的文件列表由于我们在依赖关系中已经知道,所以在依赖方法中我们可以使用$@和$^分别表示目标文件和依赖的文件列表 ,如下图我们一样可以正常执行make命令生成对应的命令。
2.5. %和wildcard,shell展开文件
(a:%
如上图所示:%.c和%.o的意思分别是将所有以.c和.o结尾的文件展开,那么%.o:%.c这句命令的意思是将该目录下所有的.c目标文件的生成依赖于对应的所有的.o文件。
(b:shell + 命令 :
如上图所示:在第3行处使用了shell + 命令的方法,即 SRC=$(shell ls *.c),我们学过 ls 的意思是列出所有的文件内容,因此这句命令的意思为将所有的以.c结尾的文件展开并赋值给SRC。此外我们使用了一组依赖关系和依赖方法验证这个结论。在test这个依赖方法中我们将SRC的内容以不回显的方法打印出来,结果为code.c和 myproc.c。同理,wildcard的作用和shell + 命令类似,这里不再讲述。
三:进度条
3.1 回车换行
如上图所示:当我们在一行中写入了123这三个数字的时候,如果换行(\n)则表示在下一行的当前位置继续输入,而回车(\r)则表示直接另起一行继续输入。而一般将 \n\r 称为回车换行
3.2 缓冲区
事例1:
事例2:
在上面两个事例中:对于第一个事例,我们可以看到我们先执行printf将hello world打印出来后休眠3秒然后程序结束;而在第二个事例中,我们是先休眠3秒才将hello world打印出来,看似好像是想执行sleep语句才执行printf语句,但是不是的。一定是将printf执行完了才执行sleep,所以是为什么printf语句执行完后显示器上却没有打印出hello world而是休眠了3秒呢,而且休眠后hello world为什么又可以打印出来并且在这休眠中hello world在哪里呢?而在第一个事例中为什么有\n就可以先打印出hello world呢?
这里解释一下:其实带\n就代表着行刷新,因此执行printf("hello world\n");这句语句时由于携带\n因此printf会先将hello world打印出来再执行sleep休眠;而执行printf("hello world\n");这句语句时由于没有携带\n和其他刷新缓冲区的命令,所以会先sleep休眠3秒,而在休眠过程中hello world一直在缓冲区中,当程序退出时会自动刷新缓冲区,因此hello world就被打印出来了。
如果我们想要达到立即刷新的功能,可以使用fflush(stdout),如下图所示:
3.3 进度条代码
process.c
1 #include "process.h"2 #include<unistd.h>3 #include<string.h>4 5 #define NUM 1016 #define STYLE '#'7 8 void process(double total,double current)9 {10 char buffer[NUM];11 memset(buffer,0,sizeof(buffer));12 13 const char *lable = "|/-\\";14 int len = strlen(lable);15 int num = (int)(current * 100 / total);16 17 int i = 0;18 for(;i <= num;i++)19 {20 buffer[i] = STYLE;21 }22 23 static int cnt = 0;24 double rate = current / total;25 cnt %= len;26 27 printf("[%-100s][%.1lf%%][%c]\r",buffer,rate * 100,lable[cnt]);28 cnt++;29 fflush(stdout);30 31 }
main.c
1 #include "process.h"2 #include<stdio.h>3 #include<unistd.h>4 5 double total = 1024.0;6 double speed = 1.0;7 8 void Download()9 {10 double current = 0.0;11 while(current <= total)12 {13 process(total,current);14 usleep(3000);15 current += speed;16 }17 printf("\nDownload %.2lfMB Done\n",current);18 }19 20 int main()21 {22 Download();23 return 0;24 }
process.h
1 #pragma once2 #include<stdio.h>3 4 void process();
Makefile
1 SRC=$(wildcard *.c)2 OBJ=$(SRC:.c=.o)3 BIN=processbar4 5 $(BIN):$(OBJ)6 gcc -o $@ $^7 8 %.o:%.c9 gcc -c $<10 .PHONY:11 clean:12 rm -f $(OBJ) $(BIN)13