Linux动态库函数的详解

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日

相关文章

  • Android学习小结之Activity保存和恢复状态

    在Android中,可以通过保存和恢复状态来确保在Activity生命周期发生变化时保留数据和用户界面的状态。以下是一个完整的攻略,用于学习如何在Activity中保存和恢复状态: 保存状态: 在Activity中,重写onSaveInstanceState方法。在该方法中,使用Bundle对象保存需要保留的数据。 java @Override protec…

    other 2023年9月5日
    00
  • stm32按键识别

    描述 在STM32单片机开发中,按键识别是一个常见的需求。本攻略将介绍如何使用STM32 HAL库实现按键识别,包括按键硬件连接、按键扫描、按键中断处理等。同时本攻略将提供两个示例说明,分别介绍如何使用按键控制LED灯的开关和如何使用按键控制LCD屏的内容。 按键硬件连接 以下是按键硬件连接的步骤: 连接按键 首先,需要将按键连接STM32单片机的GPIO引…

    other 2023年5月7日
    00
  • numpy.shape()函数

    下面是关于“numpy.shape()函数”的完整攻略: 1. 问题描述 在使用NumPy进行数组操作时,有时需要获取数组的形状信息。这使用.shape()函数来实现但是,这个函数的具体用法是什么呢? 2. 解决方法 numpy.shape()函数用获取数组的形状信息。返回一个元组,其中包含数组的维度信息。 以下是两个示例说明: 示例1:获取一维数组的形状信…

    other 2023年5月7日
    00
  • mac环境下python3安装及配置

    Mac环境下Python3安装及配置 Python是一种高级编程语言,广泛应用于Web开发、机器学习、数据分析等领域。在Mac环境下使用Python可以提高工作效率,但需要正确安装及配置Python,下面我们来介绍具体步骤。 步骤一:安装Homebrew Homebrew是Mac下最流行的包管理工具,用于简化软件安装过程。在Terminal中输入以下命令安装…

    其他 2023年3月28日
    00
  • JScript中的’var’定义变量的作用域

    JScript中的’var’定义变量的作用域 在JScript中,使用关键字’var’可以定义变量。’var’关键字的作用是声明一个变量,并将其限定在当前作用域内。在本攻略中,我们将详细讲解’var’关键字的作用域规则,并提供两个示例来说明。 作用域规则 在JScript中,’var’关键字定义的变量具有函数作用域。这意味着变量的作用域仅限于声明它的函数内部…

    other 2023年7月29日
    00
  • 7zip在dos命令行用法总结

    7zip在DOS命令行用法总结 7zip 是一款压缩/解压缩工具,安装完成后可以在命令行窗口中使用。本篇文章将详细讲解7zip在DOS命令行中的用法。 安装7zip 首先需要安装7zip,可以从官网下载最新版本的安装文件。 安装完成后,打开命令行窗口,输入“7z”命令,如果命令行窗口中出现7zip的说明,说明7zip已经安装成功。 常用命令 7zip最常用的…

    other 2023年6月27日
    00
  • html5 css3 动态气泡按钮实例演示

    HTML5 CSS3 动态气泡按钮实例演示攻略 介绍 在本攻略中,将详细讲解如何使用HTML5和CSS3来创建动态气泡按钮。该按钮具有动画效果,点击时会出现气泡扩散效果。下面将通过两个示例说明来演示实现过程。 示例1:基本按钮样式 首先,我们需要创建一个基本的按钮样式。在HTML文件中,添加以下代码: <button class="bubbl…

    other 2023年6月28日
    00
  • Windows7文件批量更名通过bat命令实现无需其他工具

    下面是详细讲解“Windows7文件批量更名通过bat命令实现无需其他工具”的完整攻略。 1. 准备工作 在开始操作之前,需要先做一些简单的准备工作。 1.1 选择要更改的文件 首先,需要确定需要更改的文件所在的文件夹,并将这些文件拷贝到一个新的文件夹中,以免造成不必要的操作错误和文件丢失。 1.2 创建新的文件夹 为了方便管理,需要在本地硬盘中创建一个新的…

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