库即二进制形式的目标模块,使用库可以很方便对程序进行模块化设计,
方便对某些固定功能的重复使用,方便对某些功能进行更新。
库与.c文件关系如下图:
库分为两种类型,即静态库和动态库;
静态库扩展名.a ,库中封装的二进制代码,在链接阶段被复制到调用模块中,
调用模块运行时不再需要静态库的支持;
动态库扩展名.so ,库中封装的二进制代码,在链接阶段不会复制到调用模块,
被嵌入到调用模块中的仅仅是被调用函数在库中的相对地址,
因此,调用模块在运行时需要动态库的支持。
动态库和静态库相比,使用更为灵活,更常见。
库的制作:
静态库的制作:
第一步:编辑源程序,包括a.c a.h . . .
第二步:源程序编译成目标文件,gcc -c a.c --->a.o . . .
第三步:打包目标文件,即把他们做成库,ar -r libxxx.a a.o b.o c.o . . .
ar命令解释:
格式:ar [选项] 静态库名 目标文件列表
选项如下:
-r:将目标文件插入到静态库,若目标文件已存在,则更新
-q:将目标文件追加到静态库的末尾
-d:从静态库中删除指定的目标文件
-t:列表形式显示静态库中的目标文件
-x:将静态库展开为目标文件
动态库的制作:
第一步:编辑源程序,包括xxx.c xxx.h
第二步:编译成目标模块,gcc -fpic -c a.c . . .
-fpic:小模式,代码量小,速度快,只支持一部分平台,比如Linux
-fPIC:大模式,代码量较大,速度较慢,支持所有平台
第三步:链接成库,gcc -shared a.o . . . -o libxxx.so
库的使用:
1、直接调用法
gcc main.c libmath.a / gcc main.c libmath.so
2、参数调用法
gcc main.c -lmath -L. //-l库名 -L库所在路径
3、设置环境变量法
静态库设置方法:export LIBRARY_PATH=$LIBRARY_PATH:.
动态库设置方法:export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:.
为了永久设置环境变量,可将上述语句写入~/.bashrc
gcc main.c -lmath
动态库的使用还可以利用Linux中的dl库实现动态加载
简单实例如下:
其中add和show是库中的函数,add 的功能是将两个数相加,返回结果;show 的功能是 printf 传进来的数
#include <stdio.h>
#include <dlfcn.h>
#include "math.h" //动态库里的头文件
#include "show.h" //动态库里的头文件
typedef int (*operation)(int,int); //给函数类型 int (*) (int,int) 起别名operation
typedef void (*d_show)(int);
int main()
{
int a,b;
void *handle = dlopen("./libmath.so",RTLD_LAZY); //获取库的句柄
if(handle == NULL)
{
printf("%s\n",dlerror());
return;
}
operation add = (operation)dlsym(handle,"add"); //“add”为库里面的函数,执行加法运算,该语句的作用是获取add函数在库里面的地址
if(add == NULL)
{
printf("%s\n",dlerror());
return;
}
d_show show = (d_show)dlsym(handle,"show");
if(show == NULL)
{
printf("%s\n",dlerror());
return;
}
printf("请输入两个整数:");
scanf("%d %d",&a,&b);
printf("%d + %d = ",a,b);
show(add(a,b)); //show,add为本文件的变量,不是库里面的函数名
dlclose(handle);
return 0;
}