⑵用dlopen函数打开库文件,并指定打开方式
dllope的的第一个参数为共享库的名称,将会在下面位置查找指定的共享库。
①环境变量LD_LIBRARY_PATH列出的用分号间隔的所有目录。
②文件/etc/ld.so.cache中找到的库的列表,由ldconfig命令刷新。
③目录usr/lib。
④目录/lib。
⑤当前目录。
第二个参数为打开共享库的方式。有两个取值
①RTLD_NOW:将共享库中的所有函数加载到内存
②RTLD_LAZY:会推后共享库中的函数的加载操作,直到调用dlsym()时方加载某函数
⑶用dlerror()函数测试是否打开成功,并进行错误处理;
⑷用dlsym获得函数地址,存放在一个函数指针中
⑸用获得的函数指针进行函数调用。
⑹程序结束时用dlclose关闭打开的动态库,防止资源泄露。
⑺用ldconfig工具把动态库的路径加到系统库列表中
1、编写测试文件
//main.c 测试动态库显式调用的程序
#include<
dlfcn.h
> //用于动态库管理的系统头文件
#include"myalib.h" //要把函数的头文件包含进来,否则编译时会报错
int main(intargc,char* argv[])
//声明对应的函数的函数指针
void(*pTest)();
//加载动态库
void*pdlHandle = dlopen("libtest.so", RTLD_LAZY);
//错误处理
if(pdlHandle == NULL ) {
printf("Failed load library\n");
return -1;
char* pszErr = dlerror();
if(pszErr != NULL)
printf("%s\n", pszErr);
return -1;
//获取函数的地址
pTest = dlsym(pdlHandle, "test");
pszErr = dlerror();
if(pszErr != NULL)
printf("%s\n", pszErr);
dlclose(pdlHandle);
return -1;
//实现函数调用
(*pTest)();
//程序结束时关闭动态库
dlclose(pdlHandle);
return0;
2、编译测试文件使用-ldl选项指明生成的对象模块需要使用共享库
gcc -o main -ldlmain.c
执行完后就生成了一个main文件
3、执行测试程序
执行 ./main
说明成功。
----------------------------------分割------------------------------------------
//say.c
#include <stdio.h>
int say(char **str){
printf("%s\n",str);
}
|
将say.c 生成共享库的编译:
gcc -o dlopen.so -shared say.c
//使用dlopen函数动态加载库的源代码
#include <stdio.h>
#include <dlfcn.h>
#include <unistd.h>
void show_help(char *msg){
if(msg == NULL){
printf("Usage:mydlopen dlopen.so say stringtosay\n");
}else{
printf("%s\n",msg);
}
exit(1);
}
int main(int ac,char ** av){
if(ac < 3){
show_help(NULL);
}
void *handle;
//void *pfunc;
int (*pfunc)(char *str);
char * filename = av[1];
char * func = av[2];
char * word = av[3];
char * error;
handle = dlopen(filename,RTLD_LAZY);
if(!handle){
printf("Error: handle\n");
return 1;
}
pfunc = (int (*)(char *))dlsym(handle,func);
if((error=dlerror()) != NULL){
printf("Error: dlsym\n");
return 2;
}
(*pfunc)(word);
dlclose(handle);
return 0;
}
|
//编译命令:
gcc -o mydlopen mydlopen.c -ldl
注意事项:
1.dlsym返回的指针是无类型的,要转换的指定的函数的类型。
2.使用函数指针时的写法: (*pfunc)(word); 不能直接写成pfunc(word);会段错误的
3.C还不支持默认参数,写show_help时不能给msg以NULL的默认值
3.编译时要使用共享库dl 其中有dlopen dlsynmdlerror dlclose 函数
使用命令:
./mydlopen ./dlopen.so say aaaabbbdddd
------------------------------------分割------------------------------------------
说明:pfunc = (int(*)(char *))dlsym(handle,func);
其中char *是将参数强转,因为int (*pfunc)(char*str);是这样定义的。
如果int (*pfunc)(char *str,int number);这样定义,那么强转的时候应该这样写:
pfunc = (int(*)(char *,int))dlsym(handle,func);
--------------------------------------分割-----------------------------------------
编译的时候的说明,比如现在的文件目录树如下:
1.work/
2.|--head.h
3.|--main.c
4.|--func.c
5.|--func2.c
这个时候欲将func2.c编译成动态链接库dlfunc.so,而func2.c中的函数用到了head.h和func.c里面的变量和函数,这个时候应该使用命令:
gcc -o dlfunc.so-shared func2.c func.c -I./
这样就生成了dlfunc.so。
然后编译连接主程序。
gcc -o test main.c-ldl -I./
动态库的显式调用 显式调用的含义是代码出现库文件名,用户需要自己去打开和管理库文件。其要点为:⑴把dlfcn.h系统头文件包含进来⑵用dlopen函数打开库文件,并指定打开方式dllope的的第一个参数为共享库的名称,将会在下面位置查找指定的共享库。
库的存在极大的提高了C/C++程序的复用性,但是库对于初学者来说有些难以驾驭,本文从
Linux
的角度浅谈
Linux
下的静态库、
动态
库和
动态
加
载
库。
Linux
库类型
Linux
下可以创建两种类型的库:
1、静态库(.a): 在链接期间被应用程序直接链接进可执行
文件
2、
动态
链接库(.
so
):
动态
库还分为两种用法: a) 应用程序运行期间链接
动态
库,但是在编译期间声明
动态
库的存在,也是说这种
动态
库必须在编译时对编译器可见,但编译器却不将此种库编译进可执行
文件
; b) 在运行期间,
动态
加
载
和卸
载
的库,使用
动态
加
载
方法
加
载
。这种库的形式跟
动态
链接没有本质区别,区别是在调用时
linux
下
动态
库
今天无意间发现在
linux
下share object(dynamic library)中的函数竟然可以不通过回调的方式直接访问主程序中的函数,瞬间颠覆以前对于
动态
库的观念.
1、如代码所示libhi.
so
中有一个函数hello, 主程序main中有一个函数hi_out, 那么在main中调用libhi.
so
中的hello时,hello会自动找到main程序中的hi_output函数地址, 然后进行调用.
=================hi.c 编译为 libhi.
so
=...
背景:不同产品组将其功能编译为.
so
,这些.
so
可以
加
载
到统一的基础平台上运行,如果产品组代码有改动,只需要更新对应的.
so
问题:如何
动态
加
载
.
so
文件
,并使用里边的函数/类 ?
解决方法1: 使用类的多态特性,将各种产品功能抽象为“工作类”,这些“工作类”都继承一个“
动态
加
载
基类”,然后定义纯C的类创建和销毁函数,产品功能.
so
加
载
进来后,基础平台寻找创建和销毁函数,就可以创建一个“工作...
#define INITIALIZER(f) \
static void f(void) __attribute__((constructor)); \
static void f(void)
#define DEINITIALIZER(f) \
static void f(void) __attribute__((destructor)); \
static void f(void)
#endif
在
Linux
中,Qt可以通过使用QLibrary类来
加
载
动态
链接库(.
so
文件
)。QLibrary类提供了一个简单的接口,可以在运行时
动态
加
载
和卸
载
共享库。以下是
加
载
.
so
文件
的步骤:
1. 在Qt项目中包含QLibrary头
文件
。
2. 创建QLibrary对象并指定.
so
文件
的路径。
3. 使用QLibrary对象的load()函数
加
载
.
so
文件
。
4. 使用QLibrary对象的re
so
lve()函数获取.
so
文件
中的函数指针。
5. 使用函数指针调用.
so
文件
中的函数。
6. 使用QLibrary对象的unload()函数卸
载
.
so
文件
。
例如,以下代码演示了如何
加
载
并调用一个名为libtest.
so
的
动态
库中的函数:
#include <QLibrary>
#include <QDebug>
int main()
// 创建QLibrary对象并指定.
so
文件
的路径
QLibrary lib("libtest.
so
");
//
加
载
.
so
文件
if (lib.load()) {
// 获取.
so
文件
中的函数指针
typedef int (*testFunc)(int);
testFunc func = (testFunc)lib.re
so
lve("test");
// 调用.
so
文件
中的函数
if (func) {
int result = func(5);
qDebug() << "Result: " << result;
else {
qDebug() << "Failed to re
so
lve function.";
// 卸
载
.
so
文件
lib.unload();
else {
qDebug() << "Failed to load library.";
return ;