Discuz! BBS

 找回密码
 立即注册
搜索
热搜: 活动 交友 discuz
查看: 823|回复: 0

有关Linux下C的动态链接库

[复制链接]

254

主题

363

帖子

2431

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
2431
发表于 2023-11-27 17:25:01 | 显示全部楼层 |阅读模式
0、生成动态链接库
  1. gcc test_a.c test_b.c test_c.c -fPIC -shared -o libtest.so
复制代码




1、动态链接库的隐式调用
将动态链接库和其他源程序文件或者目标文件一起链接,即为隐式调用(链接的目的是将函数的入口和函数体作一个匹配)
  1. # gcc main.c libdynamic.so -o main
复制代码

此时main.a通常无法立即运行,因为系统找不到libdynamic.so的位置。

  1. $ ldd main
  2.         linux-vdso.so.1 (0x00007fffaf12e000)
  3.         libdynamic.so (can not find it)
  4.         libc.so.6 => /lib64/libc.so.6 (0x00007f5905961000)
  5.         /lib64/ld-linux-x86-64.so.2 (0x00007f5905b79000)
复制代码
在这里就要添加动态库的位置给系统,通过修改LD_LIBRARY_PATH,即在.bash_profile等位置添加一行: export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/home/myname/mydynamiclib/  保存并执行该配置 source .bash_profile。
此时再调用ldd main.a 即可看到每一项都有入口。

2、动态链接库的显式调用
显式调用动态链接库的过程,类似于使用malloc()和free()(c++中使用new和delete)管理动态内存空间,需要时就申请,不需要时就将资源释放。
显式调用,意思是在编写代码时,利用某些函数申请调用库函数,以及之后关闭与释放库函数资源。显示调用有助于减少内存占用,更经常用于一些占用内存的大项目中。
显示调用无需引入和动态链接库相关的头文件,但需要引入<dlfcn.h>头文件,因为需要该文件提供的一些函数。
1)要显式调用,必须先打开库文件,本质上即将库文件装载到内存中。语法为:
void *dlopen(const char *filename, int flag);
filename代表库文件位置和库名。如果仅仅提供库名,则该函数会从LD_LIBRARY_PATH位置寻找库文件。
flag参数的值有两种,RTLD_NOW 将库文件所有的资源都载入内存。RTLD_LAZY: 暂时不将库文件的资源载入内存,使用时才载入。
2)借助dlsym()函数可以获得指定函数在内存中的位置。语法为:
void *dlsym(void *handle, char *symbol);
handle表示已打开库文件的指针。
symbol代表指定目标函数的函数名。
如果dlsym()函数成功找到symbol指代的函数,则handle被赋予指向该函数的指针,否则handle为NULL。
3)dlclose()关闭已经打开的动态链接库。
int dlclose(void *handle)
handle表示已打开的库文件指针。
当函数返回0时,表示函数操作成功,反之,函数执行失败。
注意,调用dlclose()函数并不一定会将目标库彻底释放,而是使目标库引用计数减1,当引用计数为零时才触发释放。
4)dlerror()函数用于获取最近一次dlopen()、dlsym()和dlclose()这些函数操作失败的错误信息。语法:
const char *dlerror(void);
该函数不需要传递任何参数。同时,如果函数返回NULL,则表示最近一次操作执行成功。
使用显式调用的例程:
  1. #include <stdio.h>
  2. #include <dlfcn.h>
  3. int main()
  4. {
  5.     int m,n;
  6.     //打开库文件
  7.     void* handler = dlopen("libmymath.so",RTLD_LAZY);
  8.     if(dlerror() != NULL){
  9.         printf("%s",dlerror());
  10.     }
  11.    
  12.     //获取库文件中的 add() 函数
  13.     int(*add)(int,int)=dlsym(handler,"add");
  14.     if(dlerror()!=NULL){
  15.         printf("%s",dlerror());
  16.     }
  17.   
  18.     //获取库文件中的 sub() 函数
  19.     int(*sub)(int,int)=dlsym(handler,"sub");
  20.     if(dlerror()!=NULL){
  21.         printf("%s",dlerror());
  22.     }

  23.     //获取库文件中的 div() 函数
  24.     int(*div)(int,int)=dlsym(handler,"div");
  25.     if(dlerror()!=NULL){
  26.         printf("%s",dlerror());
  27.     }
  28.     //使用库文件中的函数实现相关功能
  29.     printf("Input two numbers: ");
  30.     scanf("%d %d", &m, &n);
  31.     printf("%d+%d=%d\n", m, n, add(m, n));
  32.     printf("%d-%d=%d\n", m, n, sub(m, n));
  33.     printf("%d÷%d=%d\n", m, n, div(m, n));
  34.     //关闭库文件
  35.     dlclose(handler);
  36.     return 0;
复制代码
编译的指令:
  1. $ gcc main.c -ldl -o main
复制代码
其中-ldl 是gcc调用<dlfcn.h>时指明这个头文件(库文件)的命令。







02_16x9.jpg
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

Archiver|手机版|小黑屋|DiscuzX

GMT+8, 2025-4-16 09:16 , Processed in 0.018967 second(s), 21 queries .

Powered by Discuz! X3.4

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表