Linux动态库函数的详解

yizhihongxing

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_NOWRTLD_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);
}

应用程序中使用动态库的好处

  1. 动态库在使用时才会被加载,节省了内存;
  2. 动态库可以供多个程序使用,避免了不必要的重复编译。

总结

通过本文的讲解,了解了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技术站

(0)
上一篇 2023年6月26日
下一篇 2023年6月26日

相关文章

  • Java私有构造器使用方法示例

    Java私有构造器使用方法示例攻略 在Java中,私有构造器是一种特殊的构造器,它只能在类的内部被访问和调用。私有构造器通常用于实现单例模式、工具类或者禁止实例化的类。本攻略将详细讲解如何使用私有构造器,并提供两个示例说明。 使用私有构造器的步骤 以下是使用私有构造器的步骤: 在类中声明一个私有构造器。私有构造器的访问修饰符为private,这样它就只能在类…

    other 2023年8月6日
    00
  • docker菜鸟入门

    Docker菜鸟入门 什么是Docker? Docker是一个开源的容器化平台,可以让你将你的应用程序和依赖项打包成一个可移植的容器,然后在任何 Docker 容器运行时环境上运行这个容器。通过使用 Docker,你可以确保你的应用程序在不同的环境和平台上运行一致,而不需要担心因为不同的环境和平台而出现的问题。 Docker的优势 便携性:Docker容器可…

    其他 2023年3月28日
    00
  • insertinto语句的基本用法

    以下是详细讲解“insert into语句的基本用法”的标准Markdown格式文本: insert into语句的基本用法 insert into语句是用于向数据库表中插入数据的SQL语句。本文将介绍insert into语句的基本概念、使用方法和两个示例说明。 1. insert into语句基本概念 insert into语句是用于向数据库表中插入数据…

    other 2023年5月10日
    00
  • OPPOFindX6Pro开发者选项在哪 OPPOFindX6Pro进入开发者模式教程

    下面是关于“OPPO Find X6 Pro开发者选项在哪,如何进入开发者模式”的完整攻略。 OPPO Find X6 Pro开发者选项在哪 开启OPPO Find X6 Pro的开发者选项需要先找到该选项在手机设置中的位置。步骤如下: 打开手机设置; 向下滑动页面,找到“系统与更新”选项; 点击进入“系统与更新”页面; 向下滑动页面,找到“关于手机”选项,…

    other 2023年6月26日
    00
  • 利用C++实现简易的.ini配置文件解析器

    我来为你详细讲解一下“利用C++实现简易的.ini配置文件解析器”的完整攻略。 1. 需求分析 在开始编写代码之前,我们需要明确从.ini文件中读取配置信息的需求。- 首先,我们需要能够读取.ini文件中的各个section及其相应的配置项。- 其次,我们需要对读取到的配置项进行相应的数据类型转换(如字符串转整数)。- 最后,我们需要能够获取到读取到的配置项…

    other 2023年6月25日
    00
  • jenkins配合dockerfile部署项目

    以下是关于“jenkins配合dockerfile部署项目”的完整攻略,包括基本概念、解决方法、示例说明和注意事项。 基本概念 Jenkins是一种开源的自动化部署工具可以帮助开发人员自动化构建、测试和部署软件。Docker是一种容器化技术,可以将应用程序和其依赖项打包到一个容器中,以便在不同的环境中运行。Jenkins可以与Dockerfile配合使用,以…

    other 2023年5月7日
    00
  • 怎么扫描文件到电脑

    当我们需要将纸质文件或图片转化为电子版本时,我们需要使用扫描仪来完成。下面是扫描文件到电脑的完整攻略: 第一步:准备工作 预先安装扫描仪的驱动程序,或者连接一台有扫描仪功能的多功能打印机。 确保连接电脑和扫描仪的电缆连接正常。 根据需要选择合适的文件格式,如PDF、JPG、PNG等。 第二步:设置扫描选项 打开扫描软件,选择扫描选项。 设置扫描分辨率,一般建…

    其他 2023年4月16日
    00
  • finaldraft(专业剧本编辑器)

    以下是关于“Final Draft(专业剧本编辑器)”的完整攻略,过程中包含两个示例。 背景 Final Draft是一款专业的剧本编辑器,广泛用于电影、电视、戏剧等领域。提了许多功能,如自动格式化、场景管理、角色管理、剧本分析等。本攻略将介绍如何使用Final Draft进行本创作。 基本理 使用Final Draft进行剧本创作,我们需要完成以下步骤: …

    other 2023年5月9日
    00
合作推广
合作推广
分享本页
返回顶部