【链接库】静态库与动态库区别?

在C语言中,函数库分为两种类型,一种是静态库(库程序是直接注入目标程序,不分彼此,库文件通常以.a结尾),另一种为动态库(库程序是在运行目标程序时加载,库文件通常以.so结尾)。

文件到可执行文件的编译过程:

image

静态库 VS 动态库

静态库特点:

静态库的代码在编译的过程中就已经载入可执行文件中,所以最后生成的可执行文件相对较大。

静态库在链接的时候把库直接加载到程序中

静态库的名字一般是libxxx.a在编译时可以直接编译进可执行文件中,运行环境中可以不存在库文件,但是如果库文件更新了,可执行文件需要重新编译

编译生成静态库:

gcc -c hello.c
ar crv libhello.a hello.o    # 将目标文件Hello.o打包成静态库文件

调用静态库:

gcc main.c -L . -lhello   (-L后面是静态库文件所在目录)

动态库特点:

动态库的代码在可执行文件运行时才载入内存,在编译过程中仅简单的引用,所以最后生成的可执行文件较小。

动态库链接的时候,只是保留接口,将动态库和程序代码独立,这样可以提高代码的可复用度和降低程序的耦合度

动态库的代码是可执行文件在运行中加载执行,也就是说,程序运行环境中要有动态库文件,一般以libxxx.so命令,优点是方便升级,动态库更新,可执行文件不用重新编译

编译生成动态库

gcc -fPIC -shared -o libhello.so hello 
(-fPIC是常见与地址无关的编译程序,为了在多个应用程序间共享, -shared指定生成动态连接库)

调用动态库

一般在运行环境中直接运行可执行文件,前提动态库文件也在运行环境中,需要注意的是系统在运行程序的时候,需要知道动态库的名称和位置,这样才能加载,如果找不到动态库就会直接程序退出报错。一般Linux系统会把/lib和/usr/lib两个目录作为默认的库搜索路径,所以动态库编译成功后,就将文件放到这两个目录下方便寻找。

当然也可以配置/etc/ld.so.conf文件来添加其他的搜索路径,将需要库文件的绝对路径一行一行的添加进去,或者在环境变量LD_LIBRARY_PATH 中指明库的搜索路径,比如:export LD_LIBRARY_PATH=/opt/gtk/lib:$LD_LIBRARY_PATH。

编译可执行程序的时侯也可以使用下面方式 -L 显式的链接动态库编译:

gcc main.c -o main -L ./ -lhello
(-L后面是库文件的路径,最好是绝对路径。-l加上去掉lib的库名。然后执行可执行文件就可以了)

还有一种加载动态库的方式:

linux提供dlopen、dlsym、dlerror和dlclose函数获取动态链接库的函数。通过这四个函数可以实现一个插件程序,方便程序的扩展和维护。格式如下:

#include <dlfcn.h>

// 用dlopen函数打开库文件,并指定打开方式
void *dlopen(const char *filename, int flag);

// 用dlerror()函数测试是否打开成功,并进行错误处理;
char *dlerror(void);

// 用dlsym获得函数地址,存放在一个函数指针中
void *dlsym(void *handle, const char *symbol);

// 程序结束时用dlclose关闭打开的动态库,防止资源泄露
int dlclose(void *handle);

使用这些函数去找对应的库函数入口地址,然后执行。










参考文章:
https://developer.aliyun.com/article/484669
https://zhuanlan.zhihu.com/p/307640255

posted @ 2022-11-14 21:52  Emma1111  阅读(192)  评论(0编辑  收藏  举报