dlopen和 dlsym的使用方式

2023-10-30

背景

为了把不同的逻辑解耦,一般会把各个业务封装成动态库,然后主逻辑去调用各个动态库。这里有个问题是,为什么以前我们都是通过include第三方的头文件,然后通过连接器链接动态库实现,现在却要利用dlopen呢?考虑以下情况,比如我们要用cublas这个库的sgemm函数。

#include "cublas.h"
int main()
{
	cublas:: Mat a, b;
	cublas::sgemm(a,b);
}

我们知道cublas是英伟达提供的,人家每年都要更新动态库的,比如今年更新后,动态库的头文件改了cublas_v2.h, 函数名改为sgemm_v2, 这样一顿操作后,你不仅要升级库,也要修改已经上线的代码,假如这个sgemm函数在你源码中出现了n多次,这将是一个灾难。但是通过下面的方式你就可以避免这个问题:

// func.h
#include <stdio.h>
#include <stdlib.h>
#include <cublas_v2.h> // 如果你知道确切的函数返回信息,这个对应下面的cublas_func可以自己写。
#include <dlfcn.h>
extern std::once_flag cublas_dso_flag;
extern void *cublas_dso_handle;

  struct DynLoad__add {                                                
    template <typename... Args>                                             
    inline auto operator()(Args... args) -> DECLARE_TYPE(add, args...) 
    { 
      using cublas_func =  decltype(::add(std::declval<Args>()...)) (*)(Args...);         
      std::call_once(cublas_dso_flag, []() {                                
        cublas_dso_handle = dlopen("./libcublas.so", RTLD_LAZY);       
      });                                                                   
      static void *p_add = dlsym(cublas_dso_handle, "add");          
      return reinterpret_cast<cublas_func>(p_add)(args...);            
    }                                                                       
  };                                                                        
  extern DynLoad__add add;
// func.c
DynLoad__add add;

// main.cc
#include <stdio.h>
#include <stdlib.h>
#include "func.h"
int main()
{
    add(2,7));
}

根据上面的代码可以看到,只要你每次修改func.h文件的动态库路劲和函数名就可以了,其他用到的add函数根本不需要再去修改。真是很方便,上面的代码参考paddle的源码:paddle/fluid/platform/dynload/cublas.h

demo

生产动态库

int add(int a,int b)
{
    return (a + b);
}

int sub(int a, int b)
{
    return (a - b);
}

gcc -fPIC -shared caculate.c -o libcaculate.so

调用dlopen

#include <dlfcn.h>

void *dlopen(const char *filename, int flag);

char *dlerror(void);

void *dlsym(void *handle, const char *symbol);

int dlclose(void *handle);

dlopen是加载动态链接库,flag可以设置不同的模式(RTLD_LAZY 暂缓决定,等有需要时再解出符号, RTLD_NOW 立即决定,返回前解除所有未决定的符号。), dlopen可以返回动态库的句柄,dlsym是获取动态库中的具体函数名或者变量名。dlopen是关闭动态库。

#include <stdio.h>
#include <stdlib.h>
#include <dlfcn.h>
typedef int (*FUNC)(int, int);
int main()
{
    void *handle;
    char *error;
    FUNC func = NULL;

    //打开动态链接库
    handle = dlopen("./libcaculate.so", RTLD_LAZY);
    //获取一个函数
    void* tmp= dlsym(handle, "add");
    FUNC func = reinterpret_cast<FUNC>(tmp);
    printf("add: %d\n", (*func)(2,7));
    //printf("add: %d\n", func(2,7)); 这两种写法都正确,函数指针的解引用符号等于自己不做处理,建议用第二种写法,直观。
    //关闭动态链接库
    dlclose(handle);
}

gcc -rdynamic -o main main.c -ldl

参考链接

https://www.cnblogs.com/Anker/p/3746802.html

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

dlopen和 dlsym的使用方式 的相关文章

随机推荐

  • 【blender建模功能】03 倒角工具

    blender 03 倒角工具 基操 宽度类型 其他参数 倒角问题 顶点倒角 1 基础操作 2 宽度类型 3 其他参数 3 1 材质编号 3 2 平滑 3 2 1 自动光滑 3 2 2 硬化法线 3 3 钳制重叠 3 4 外衔接 内衔接 3
  • UE4联网2——视角同步

    在做完子弹的同步后发现和客户端和服务器的玩家的仰角是不同步的 所以在角色代码中加入tick函数更新玩家的仰角pitch 这里我们需要用到一个变量RemoteViewPitch 这是在pawn中定义的已经复制的公有变量 rpc 值得注意的是它
  • 忽略大小写的字符串比较

    问题描述 一般我们用strcmp可比较两个字符串的大小 比较方法为对两个字符串从前往后逐个字符相比较 按 ASCII 码值大小比较 直到出现不同的字符或遇到 0 为止 如果全部字符都相同 则认为相同 如果出现不相同的字符 则以第一个不相同的
  • vue3引用ElementPlus出错|如何在vue中引用TypeScript

    具体错误 直接套用elementplus官方文档里的模版 报错 Module parse failed Unexpected token You may need an additional loader to handle the res
  • 运放噪声如何计算?

    一 噪声 运放的噪声分为 1 电压噪声en v 2 电流噪声在电阻Rs和R1 R2上产生的等效噪声en i 3 电阻的热噪声enr 总输入噪声计算公式 en in sqrt env 2 eni 2 enr 2 总输出噪声计算公式 en ou
  • [第七届蓝帽杯全国大学生网络安全技能大赛 蓝帽杯 2023]——Web方向部分题 详细Writeup

    Web LovePHP 你真的熟悉PHP吗 源码如下
  • 【C++】C++入门

    目录 一 C 关键字 二 命名空间 2 1命名空间的定义 2 2命名空间的使用 2 2 1加命名空间名称和作用域限定符 2 2 2使用using 将命名空间中某个成员引入 2 2 3使用using namespace将命名空间引入 三 C
  • 【KnowledgeBase】CLIP多模态代码试玩

    文章目录 前言 一 CLIP整体流程简述 二 代码试玩 参考 前言 多模态CLIP的推理部分代码简单试玩一下 致敬大佬的CLIP 论文链接 Learning Transferable Visual Models From Natural L
  • JS中的“&&”与“&”和“

    在JavaScript中 和 是逻辑运算符 和 是位运算符 四个运算符主要区别是运算方法不一样 1 JavaScript中的位运算符 运算方法 两个数值的个位分别相与 同时为1才得1 只要一个为0就为0 举个例子 31 2 结果为2 理由
  • python-报错

    报错 异常名称 描述 BaseException 所有异常的基类 SystemExit 解释器请求退出 KeyboardInterrupt 用户中断执行 通常是输入 C Exception 常规错误的基类 StopIteration 迭代器
  • JS 统计字符

    var str id content value replace r n g n var length t str length
  • 使用Koa2进行Web开发(一)

    这篇文章是我正在进行写作的 新时期的Node js入门 的一部分 Connect Express与Koa 为了更好地理解后面的内容 首先需要梳理一下Node中Web框架的发展历程 Connect 在connect官方网站提供的定义是 Con
  • Python实现贝叶斯优化器(Bayes_opt)优化卷积神经网络回归模型(CNN回归算法)项目实战

    说明 这是一个机器学习实战项目 附带数据 代码 文档 视频讲解 如需数据 代码 文档 视频讲解可以直接到文章最后获取 1 项目背景 贝叶斯优化器 BayesianOptimization 是一种黑盒子优化器 用来寻找最优参数 贝叶斯优化器是
  • 从枚举类型的ordinal()方法说起

    文章背景 本周有一个开发任务涉及到了枚举类型的修改 需要对枚举类型新增一项 在新增的时候我没有加在已有项的最后面 而是在中间随便找了个位置 其实也不是很随便 我是根据语义关联性觉得放在某一项后面比较合适 没想到的是 我的无心之举经造成了大
  • 安装centos 8

    安装centos 8 首先下载centos 8镜像 地址 http mirrors aliyun com centos 8 isos x86 64 这里选择了boot版本 boot版与完整版的区别是体积小 通过网络源安装 下载完成大概有70
  • Solidity与dapp开发学习记录4

    目录 函数修饰符进阶 Payable修饰符 运用 取款 Withdraws 运用 准备好设计僵尸对战 随机数 Random Numbers 通过keccak256生成随机数 此方法容易受到不诚实节点的攻击 如何在以太坊中安全地生成随机数 运
  • BASE64Encoder及BASE64Decoder的正确用法

    一直以来Base64的加密解密都是使用sun misc包下的BASE64Encoder及BASE64Decoder的sun misc BASE64Encoder BASE64Decoder类 这人个类是sun公司的内部方法 并没有在java
  • 腾讯云搭建邮局

    想在个人电脑上面搭个邮局临时用一下 没有想到宽带的端口全部被封了 25 110 143本来以为不能发就算了 收也不行了 完全没有办法用 还好腾讯云有按月开通的 先开通一个月试试 花了三十块 开了一个 轻量应用服务器 这里安全方面 没有什么要
  • 系统架构设计高级技能 · 层次式架构设计理论与实践

    现在的一切都是为将来的梦想编织翅膀 让梦想在现实中展翅高飞 Now everything is for the future of dream weaving wings let the dream fly in reality 点击进入系
  • dlopen和 dlsym的使用方式

    背景 为了把不同的逻辑解耦 一般会把各个业务封装成动态库 然后主逻辑去调用各个动态库 这里有个问题是 为什么以前我们都是通过include第三方的头文件 然后通过连接器链接动态库实现 现在却要利用dlopen呢 考虑以下情况 比如我们要用c