1.了解
头文件:
#include<stdio.h>
<>代表区系统路径下查找头文件 /usr/include
#include"head.h"
""代表先去当前路径下查找头文件,找不到再去系统路径下查找
头文件也就是以.h结尾的文件,其中包含:宏定义、结构体、共用体和枚举的定义、函数声明、外部引用、其他头文件、重定义typedef、条件编译
源文件:
包含main函数的xx.c
包含子函数的xx.c,封装的函数需要在头文件里放声明
库文件(不能包括main函数)
2.库的定义
当使用别人的函数时除了包含头文件以外还可以用库文件。
头文件:函数声明、结构体、共用体、枚举的定义、宏定义、重定义、外部引用、其他头文件。
库:把一些常用的函数的目标文件打包在一起,提供相应的函数接口,便于程序员使用。本质上来说库是一种可执行代码的二进制形式文件。
由于windows和linux的本质不同,因此而这库的二进制是不兼容的。(Linux中的C运行库是glibc, 由GUN发布。)
3.库的分类
静态库和动态库,本质的区别时代码被载入的时刻不同。
3.1 静态库
静态库在程序编译时会被复制到目标代码中,以.a结尾。
优点:程序运行时将不再需要该静态库,运行时无需加载库,运行速度更快,可移植性好。
缺点:静态库中的代码复制到了程序中,因此体积较大;静态库升级后,程序需要重新编译链接。
3.2 动态库
动态库是在程序运行的时候才被载入代码中。也叫共享库,以.so结尾。
优点:程序在执行时加载动态库,代码体积小;程序升级更简单。
不同应用程序如果调用相同的库,那么在内存里只需要有一份该共享库的实例。
缺点:运行时还需要动态库的存在,移植性较差。运行速度慢。
4.静态库的制作
1.将源文件编译生成目标文件
gcc -c fun.c -o fun.o
2.创建静态库用ar命令,将多个.o转换成.a
ar crs libfun.a fun.o
静态库文件名的命名规范是以lib为前缀,接着就是静态库的名字,扩展名为.a。
3.测试使用静态库: gcc
gcc main.c -L. -lfun //-L指定库的路径, -l指定库名
./a.out //执行可执行文件
例子:先分文件编程
把fun.c做成静态库然后编译连接静态库
5.动态库的制作
1.用gcc来创建共享库
gcc -fPIC -c fun.c -o fun.o //-fPIC创建与地址无关的编译程序
gcc -shared fun.o -o libmyfun.so //生成动态库
2.测试使用动态库
gcc main.c -L. -lmyfun
./a.out: 可以正常编译通过,但是运行时报错
error while loading shared libraries: libmyadd.so: cannot open shared object file: No such file or directory
原因:当加载动态库时,系统会默认从/lib或/usr/lib路径下查找库文件,所以不用-L加路径了, 直接gcc main.c -lmyfun 就可以了
解决方法(有三种):
1.把库拷贝到/usr/lib和/lib目录下。(此方法编译时不需要指定库的路径)
2.在LD_LIBRARY_PATH环境变量中加上库所在路径。
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:.
(终端关闭,环境变量就没在了)
3.添加/etc/ld.so.conf.d/*.conf文件。把库所在的路径加到文件末尾,并执行ldconfig刷新
sudo vi xx.conf
添加动态库存在的路径,如:
/home/work/lib
6.总结静态库和动态库
静态库:编译阶段,体积大,移植性好,升级麻烦。
动态库:运行阶段,体积小,移植性差,升级简单。
静态库编译出来的程序体积大如图所示:
7.升级静态库和动态库
升级静态库:需要重新编译链接
升级动态库:只需要修改源文件重新制作动态库,不需要重新编译链接了,因为是在执行的时候才加载库的代码。
-L 路径:指定静态库的路径
-l(小写的L) 库名:指定库名
-I(大写i) 路径:指定头文件的路径,如果不指定默认的就是/usr/include
<> //从系统路径下查找头文件
"" //先从当前路径下查找头文件,没找到再去系统路径下查找
ldd 可执行文件名:查看链接的动态库
补充:
同名的静态库和动态库:默认优先使用动态库,如果想使用静态库 需要在后面加 -static,这是内核规定的。
如果链接没有lib前缀的库文件,可以直接用-指定库的全名无需加l选项。