(1) 静态库
如果程序使用了静态库中的函数,那么在程序的链接阶段静态库中的函数将会被链接到程序中,最终与程序的一起形成可执行文件的一部分,在此以后静态库也就不再需要了。
优点:由于已被直接加载到程序中,所以程序的运行不再依赖其他函数库的存在。
缺点:占用内存空间,由于多个应用程序或者单个应用程序内部需要多次用到静态库中的函数,那么在程序的运行结果就会有多个函数的副本存在,这样会损失很多内存空间;如果静态库中的函数发生了改变,那么依赖该函数的其他应用程序都需要重新编译。
(2) 共享库
如果程序中调用了共享库中的函数,那么在程序的编译阶段共享库中的函数不会被连接到程序中,而是在程序的运行阶段被动态的调用。Linux系统中的共享库和Windows系统下的动态库相似。
优点:节省内存空间,如果一个程序运行时需要用到共享库中的函数,那么操作系统会检查内存中是否存在该函数的副本,如果不存在就会将函数副本拷贝到内存中,否则将直接调用不需拷贝,这样多个程序可以共用一个函数的副本,节省了内存空间的占用;函数库的更新独立于依赖该函数库的程序,所以如果动态库中的函数发生了改变,那么以来该函数的程序无需进行重新编译。
缺点:程序的运行依赖于共享库文件的存在。
(3) 静态库创建实例
首先,通过VI编辑两个源文件fun1.c和fun2.c,两个函数的代码依次为:
//fun1.c #include<stdio.h> void fun1(char *arg) { printf("Fun1:Hello %s",arg); } //fun2.c #include <stdio.h> void fun2(char *arg) { printf("Fun2:Hello %s"); }
然后在终端对这两个文件进行编译:
$gcc -c fun1.c fun2.c
这时会生成两个后缀名为.o的文件fun1.o和fun2.o,然后我们将这两个文件链接成一个静态库,在终端输入:
$ar crv libfun.a fun1.o fun2.o
其中libfun.a是我们最终生成的静态库文件名称,其命名规则为:lib+名称+.a,也就是说fun才是我们真正的静态库名称。这样我们就可以用这个静态库进行编程了,首先利用VI编写带有main函数的主程序myprogram.c,代码如下:
#include<stdio.h> int main() { fun1("chao"); fun2("wei"); return 1; }
在终端对myprogram.c进行编译,输入:
$gcc -c myprogram.c
此时会生成一个myprogram.o的文件,最后将该文件与前面的静态库文件libfun.a进行链接,这样就能产生可执行程序了,需要在终端输入:
$gcc -o m_pro myprogram.o -L. -lfun
其中,-o表示是进行链接产生可执行文件,m_pro是可执行文件的名字,-L后面表示是静态库的路径,此处用“.”表示当前目录,-l后面是静态库的名字,这样就会产生一个m_pro的可执行程序,在终端就可运行:
$./m_pro Fun1:Hello chao Fun2:Hello wei
(4) 共享库创建实例
首先利用VI编辑f1.c:
#include <stdio.h> int run() { printf("I'm f1\n"); }
编译成共享库:
$gcc f1.c -o libf.so -fpic –shared
-shared 是指定编译成共享库。
-fpic是一个代码位置无关的选项。
这样就会生成一个名位libf.so的共享库文件,其命名规则和静态库一样。下面对main函数所在的源文件进行编辑,可以有两种方法:
I.显式调用方法:
#include <stdio.h> #include <dlfcn.h> int main() { void * hdl = dlopen("./libf.so", RTLD_LAZY); if (hdl == NULL) { perror("No so file"); return 1; } void (*run)() = dlsym(hdl, "run"); char *error = dlerror(); if (error) { perror("so file fail"); return 1; } run(); return 0; }
使用到了三个函数(头文件dlfcn.h):
dlopen():打开共享库,第一个参数问文件名,第二个参数是打开方式一般为RTLD_LAZY。成功则返回“句柄”,否则返回NULL。
dlsym():获取共享库中的函数指针,第一个参数为句柄,第二个参数是函数名。
dlerror():检查操作是否失败,失败返回错误字符串。否则返回NULL。
编译:
#gcc main.c -o main -ldl
-ldl是连接dl,既上面三个函数的实体。
运行得到结果I'm f1
II.隐式调用方法
int main() { run(); return 0; }
编译:
#gcc main.c -o main -L. -lf注意要将libf.so复制到/lib或/usr/lib下main才能运行。
运行结果与方法一相同。