Linux动态库函数的详解
动态库是一种可以被程序在运行时动态加载,卸载,并可以供多个程序共享的库文件。一般以.so
文件作为文件扩展名。
Linux中通过dlopen()
函数动态加载动态库,通过dlsym()
函数获取动态库中定义的函数符号,通过dlclose()
函数卸载动态库。
动态库的编译
1.生成动态库
通过gcc编译一个动态库,需要使用-shared
选项。
gcc -shared -fPIC -o libtest.so test.c
其中,-fPIC
选项指定生成位置相关的代码(位置独立代码),这是创建动态库必须的选项之一。
2.链接动态库
在使用生成的动态库时,需要通过-l
选项指定动态库的文件名(不需要包含.so
后缀),通过-L
选项指定动态库所在的路径。
gcc -o app app.c -L. -ltest
动态库依赖性
程序可执行文件在运行时会在系统中查找依赖的动态库,一般先在程序同目录下查找,然后在LD_LIBRARY_PATH
路径下查找,最后在系统预设路径下查找。可以使用ldd
命令查询程序运行时依赖的动态库。
ldd app
动态库函数调用
1.dlsym函数
使用dlsym()
函数获取动态库中定义的函数符号。同时,为了避免符号命名的冲突,一般使用注释掉的格式传递函数名称。
#include <dlfcn.h>
void *dlopen(const char *filename, int flag);
void *dlsym(void *handle, const char *symbol);
char *dlerror(void);
int dlclose(void *handle);
其中,filename
指定动态库文件的名称,flag
可以取RTLD_NOW
和RTLD_LAZY
两个值,分别表示所有函数在库打开时就绑定,以及在函数被执行时才会进行绑定。dlsym()
返回被查找符号的地址,如果查找失败,返回NULL。dlerror()
返回错误原因信息。
2.示例
假设动态库文件libtest.so
定义了函数hello()
,在程序中调用该函数的方式如下:
#include <stdio.h>
#include <dlfcn.h>
int main()
{
void *handle;
void (*hello)(void);
char *error;
//加载动态库
handle = dlopen("./libtest.so", RTLD_LAZY);
if (!handle) {
fprintf(stderr, "%s\n", dlerror());
return 1;
}
//获取动态库中的函数符号
hello = (void (*)(void)) dlsym(handle, "hello");
if ((error = dlerror()) != NULL) {
fprintf(stderr, "%s\n", error);
return 1;
}
//调用动态库中的函数
(*hello)();
//关闭动态库
dlclose(handle);
}
应用程序中使用动态库的好处
- 动态库在使用时才会被加载,节省了内存;
- 动态库可以供多个程序使用,避免了不必要的重复编译。
总结
通过本文的讲解,了解了Linux下动态库的基本概念、编译方式、依赖性以及函数调用方法。掌握了动态库的使用方法和好处。
示例一
1.生成动态库
新建test.c文件并编写内容。
#include <stdio.h>
void hello()
{
printf("Hello, World!\n");
}
void foo(int a)
{
printf("foo with parameter %d\n", a);
}
void bar()
{
printf("bar\n");
}
编译该文件并生成动态库。
gcc -shared -fPIC -o libtest.so test.c
2.编写应用程序
新建app.c文件,内容如下。
#include <stdio.h>
#include <dlfcn.h>
int main()
{
void *handle;
void (*hello)(void);
void (*foo)(int);
void (*bar)(void);
char *error;
//加载动态库
handle = dlopen("./libtest.so", RTLD_LAZY);
if (!handle) {
fprintf(stderr, "%s\n", dlerror());
return 1;
}
//获取动态库中的函数符号
hello = (void (*)(void)) dlsym(handle, "hello");
if ((error = dlerror()) != NULL) {
fprintf(stderr, "%s\n", error);
return 1;
}
bar = (void (*)(void)) dlsym(handle, "bar");
if ((error = dlerror()) != NULL) {
fprintf(stderr, "%s\n", error);
return 1;
}
foo = (void (*)(int)) dlsym(handle, "foo");
if ((error = dlerror()) != NULL) {
fprintf(stderr, "%s\n", error);
return 1;
}
//调用动态库中的函数
(*hello)();
(*bar)();
(*foo)(1024);
//关闭动态库
dlclose(handle);
return 0;
}
编译该文件并生成可执行文件。
gcc -o app app.c -ldl
编译完成后,运行该程序,可以看到以下输出。
Hello, World!
bar
foo with parameter 1024
示例二
1.生成动态库
新建add.c文件,实现加法操作。
#include <stdio.h>
int add(int a, int b)
{
return a + b;
}
编译该文件并生成动态库。
gcc -shared -fPIC -o libadd.so add.c
2.编写应用程序
新建app.c文件,内容如下。
#include <stdio.h>
#include <dlfcn.h>
int main()
{
void *handle;
int (*add)(int, int);
char *error;
//加载动态库
handle = dlopen("./libadd.so", RTLD_LAZY);
if (!handle) {
fprintf(stderr, "%s\n", dlerror());
return 1;
}
//获取动态库中的函数符号
add = (int (*)(int, int)) dlsym(handle, "add");
if ((error = dlerror()) != NULL) {
fprintf(stderr, "%s\n", error);
return 1;
}
//调用动态库中的函数
int result = (*add)(1, 2);
printf("1+2=%d\n", result);
//关闭动态库
dlclose(handle);
return 0;
}
编译该文件并生成可执行文件。
gcc -o app app.c -ldl
编译完成后,运行该程序,可以看到以下输出。
1+2=3
本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:Linux动态库函数的详解 - Python技术站