当前位置: 首页 > news >正文

Linux下c语言实现动态库的动态调用

在Linux操作系统下,有时候需要在不重新编译程序的情况下,运行时动态地加载库,这时可以通过Linux操作系统提供的API可以实现,涉及到的API主要有dlopen、dlsym和dlclose。使用时,需要加上头文件#include <dlfcn.h> 。

dlopen介绍:打开一个动态链接库 ,函数定义如下:

void * dlopen( const char * pathname, int mode ); 
函数功能描述:在dlopen的()函数以指定模式打开指定的动态连接库文件,并返回一个句柄给调用进程。

参数说明:

pathname:动态库的名称,需要带上路径。
mode:分为这几种 
RTLD_LAZY 暂缓决定,等有需要时再解出符号 
RTLD_NOW 立即决定,返回前解除所有未决定的符号。 
RTLD_LOCAL 
RTLD_GLOBAL 允许导出符号 
RTLD_GROUP 
RTLD_WORLD 
返回值说明: 
打开错误返回空指针NULL ,若成功,返回库引用 

dlsym介绍:

该函数根据动态链接库操作句柄与符号,返回符号对应的地址。

函数定义如下:

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

函数说明:

dlsym根据动态链接库操作句柄和符号,返回符号对应的地址。使用这个函数不但可以获取函数地址,也可以获取变量地址。

参数说明:

handle:打开库文件之后的句柄。

symbol:需要从库文件查找的符号。

dlclose

dlclose用于关闭指定句柄的动态链接库,只有当此动态链接库的使用计数为0时,才会真正被系统卸载。

实验一 获取函数地址

在linux下创建一个test的工程目录。

  1. 工程目录下创建一个名为lib1.c的文件,写入如下内容:
    #include<stdio.h>
    #include<stdlib.h>
    #include <stdarg.h>void LOG(const char *format, ...)
    {va_list argptr;char buffer[2048];va_start(argptr,format);vsprintf(buffer,format,argptr);va_end(argptr);printf("%s\n", buffer);
    }void lib_function_1(void)
    {LOG("call %s!!!", __func__);
    }void lib_function_2(void)
    {LOG("call %s!!!", __func__);
    }
  2. 创建一个main.c文件,内容如下所示:
    #include<stdio.h>
    #include<stdlib.h>
    #include <dlfcn.h>void dynamic_lib_test()
    {void (*fun)();void *hander = NULL;hander = dlopen("./libshare.so", RTLD_NOW);if(hander == NULL) {printf("can not find dlib\n");return;}fun = (void(*)())dlsym(hander, "lib_function_1");if(fun==NULL) {printf("can't find function\n");}fun();fun = (void(*)())dlsym(hander, "lib_function_2");if(fun==NULL) {printf("can't find function\n");}fun();dlclose(hander);
    }int main(int argc, char *argv[])
    {dynamic_lib_test();return 0;
    }
  3. 创建一个Makefile,生成一个动态库以及可执行文件,内容如下所示:
    CPROG	= test
    BIN     = $(CPROG) 
    CC= gcc
    OBJS=main.o lib1.oLDFLAGS += -ldlall: $(BIN) 
    clean:rm -f $(OBJS) $(BIN)
    $(BIN): $(OBJS)$(CC) -g -fPIC -shared lib1.c -o libshare.so$(CC)  -o $(BIN) $(OBJS) $(CFLAGS) $(LDFLAGS) $(CFLAGS_EXTRA)
  4. 编译该工程的代码

    执行命令:make clean;make

    最终会在该工程生成一个libshare.so动态库文件以及test的可执行文件。

  5. 测试验证在该工程下执行./test,便可以观察到最终结果,如下图所示:

实验二 获取全局变量地址

  1. 在当前目录下新增lib2.c,写入如下内容:
    #include<stdio.h>
    #include<stdlib.h>
    #include<string.h>
    #include<stdarg.h>//声明一个结构体
    typedef struct test_s {char *test_name;void (*test_func)();void (*test_set_buf)(char *val);char *(*test_get_buf)();
    }test_t;char testbuf[128]="123456";void Log(const char *format, ...)
    {va_list argptr;char buffer[2048];va_start(argptr,format);vsprintf(buffer,format,argptr);va_end(argptr);printf("%s\n", buffer);
    }
    void test_function()
    {Log("function %s call!!!", __func__);
    }void test_set_buf(char *val)
    {strcpy(testbuf, val);
    }char *test_get_buf()
    {return testbuf;
    }
    //定义一个全局变量
    test_t test = {.test_name = "TestName",.test_func = test_function,.test_get_buf = test_get_buf,.test_set_buf = test_set_buf,
    };
  2. 编辑main.c,内容如下:
    #include <string.h>void dynamic_lib_test_1()
    {void (*fun)();void *hander = NULL;hander = dlopen("./libshare.so", RTLD_NOW);if(hander == NULL) {printf("can not find dlib\n");return;}fun = (void(*)())dlsym(hander, "lib_function_1");if(fun==NULL) {printf("can't find function\n");}fun();fun = (void(*)())dlsym(hander, "lib_function_2");if(fun==NULL) {printf("can't find function\n");}fun();dlclose(hander);
    }typedef struct test_s {char *test_name;void (*test_func)();void (*test_set_buf)(char *val);char *(*test_get_buf)();
    }test_t;void dynamic_lib_test_2()
    {void *hander = NULL;hander = dlopen("./libshare.so", RTLD_NOW);if(hander == NULL) {printf("can not find dlib\n");return;}test_t *t = (test_t *)dlsym(hander, "test");if(t==NULL) {printf("can't find function\n");return;}printf("name:%s, buf:%s\n", t->test_name, t->test_get_buf());t->test_func();t->test_set_buf("hello world!!!");printf("name:%s, buf:%s\n", t->test_name, t->test_get_buf());dlclose(hander);
    }int main(int argc, char *argv[])
    {dynamic_lib_test_1();dynamic_lib_test_2();return 0;
    }
    
  3. 编辑Makefile,主要是添加lib2.c的编译
    CPROG	= test
    BIN     = $(CPROG) 
    CC= gcc
    OBJS=main.o lib1.o
    LDFLAGS += -ldlall: $(BIN) 
    clean:rm -f $(OBJS) $(BIN)
    $(BIN): $(OBJS)$(CC) -g -fPIC -shared lib1.c lib2.c -o libshare.so$(CC)  -o $(BIN) $(OBJS)   $(CFLAGS) $(LDFLAGS) $(CFLAGS_EXTRA) 

 4.执行make clean;make重新编译这个工程

5.测试验证

dlsym找到全局结构体test后,可以直接用这个全局结构体指针来使用库里面的函数了。 

总结:

通过dlopen打开动态库的方式,允许在运行时动态地加载库,这可以让你在不重新编译程序的情况下,添加或修改库中的函数,同时也为程序提供了更大的灵活性。dlsym允许程序在运行时查找库中的符号(通常是函数或变量的名称)。这使得程序可以在运行时决定调用哪个版本的函数,或者根据需要选择不同的实现。由于只有当程序实际需要时才加载库,因此可以节省内存。如果多个程序共享同一个库,那么这个库只需要在内存中加载一次。使用动态链接,你可以更容易地控制库的版本。

相关文章:

Linux下c语言实现动态库的动态调用

在Linux操作系统下&#xff0c;有时候需要在不重新编译程序的情况下&#xff0c;运行时动态地加载库&#xff0c;这时可以通过Linux操作系统提供的API可以实现&#xff0c;涉及到的API主要有dlopen、dlsym和dlclose。使用时&#xff0c;需要加上头文件#include <dlfcn.h>…...

为什么MCU在ADC采样时IO口有毛刺?

大家在使用MCU内部ADC进行信号采样一个静态电压时&#xff0c;可能在IO口上看到这样的波形。这个时候大家一般会认识是信号源有问题&#xff0c;但仔细观察会发现这个毛刺的频率是和ADC触发频率一样的。 那么为什么MCU在ADC采样时IO口会出现毛刺呢&#xff1f;这个毛刺对结果有…...

C# 将 Word 转化分享为电子期刊

目录 需求 方案分析 相关库引入 关键代码 Word 转 Pdf Pdf 转批量 Jpeg Jpeg 转为电子书 实现效果演示 小结 需求 曾经的一个项目&#xff0c;要求实现制作电子期刊定期发送给企业进行阅读&#xff0c;基本的需求如下&#xff1a; 1、由编辑人员使用 Microsoft Word…...

网络世界的黑暗角落:常见漏洞攻防大揭秘

网络世界的黑暗角落&#xff1a;常见漏洞攻防大揭秘 今天带来了网站常见的漏洞总结,大家在自己的服务器上也需要好好进行防护,密码不要过于简单.不然非常容易遭到攻击,最终达到不可挽回的损失.很多黑客想网络乞丐一样将你服务器打宕机,然后要求你进行付费.不知道大家有没有遇到…...

通信领域发展方向

5G网络技术&#xff1a;随着5G网络的建设和商用推广&#xff0c;各家运营商、厂商和研究机构都在探索5G技术的应用场景和解决方案&#xff0c;如网络切片、毫米波通信、多用户MIMO等。 物联网技术&#xff1a;物联网技术已经成为通信行业的重点发展领域&#xff0c;包括传感器…...

21 3GPP中 5G NR高速列车通信标准化

文章目录 信道模型实验——物理层设计相关元素μ(与子载波间隔有关)设计参考信号(DMRS) 本文提出初始接入、移动性管理、线性小区设计等高层技术。描述3GPP采用HST场景的评估参数&#xff0c;阐释了HST应用的物理层技术&#xff0c;包括数字通信和参考信号设计&#xff0c;链路…...

【网络安全】-Linux操作系统—CentOS安装、配置

文章目录 准备工作下载CentOS创建启动盘确保硬件兼容 安装CentOS启动安装程序分区硬盘网络和主机名设置开始安装完成安装 初次登录和配置更新系统安装额外的软件仓库安装网络工具配置防火墙设置SELinux安装文本编辑器配置SSH服务 总结 CentOS是一个基于Red Hat Enterprise Linu…...

CCNP课程实验-OSPF-CFG

目录 实验条件网络拓朴需求 配置实现基础配置1. 配置所有设备的IP地址 实现目标1. 要求按照下列标准配置一个OSPF网络。 路由协议采用OSPF&#xff0c;进程ID为89 &#xff0c;RID为loopback0地址。3. R4/R5/R6相连的三个站点链路OSPF网络类型配置成广播型&#xff0c;其中R5路…...

【Spring Security】打造安全无忧的Web应用--入门篇

&#x1f973;&#x1f973;Welcome Huihuis Code World ! !&#x1f973;&#x1f973; 接下来看看由辉辉所写的关于Spring Security的相关操作吧 目录 &#x1f973;&#x1f973;Welcome Huihuis Code World ! !&#x1f973;&#x1f973; 一.Spring Security是什么 1.概…...

【每日一题】【12.20】2828.判别首字母缩略词

&#x1f525;博客主页&#xff1a; A_SHOWY&#x1f3a5;系列专栏&#xff1a;力扣刷题总结录 数据结构 云计算 数字图像处理 力扣每日一题_ 1.题目链接 2828. 判别首字母缩略词https://leetcode.cn/problems/check-if-a-string-is-an-acronym-of-words/ 2.题目描述 今天…...

LabVIEW开发振动数据分析系统

LabVIEW开发振动数据分析系统 自动测试系统基于LabVIEW平台设计&#xff0c;采用了多种高级硬件设备。系统的硬件组成包括PCB振动加速度传感器&#xff0c;这是一种集成了传统压电加速度传感器和电荷放大器的先进设备&#xff0c;能够直接与采集仪器连接。此外&#xff0c;系统…...

去掉乘法运算的加法移位神经网络架构

[CVPR 2020] AdderNet: Do We Really Need Multiplications in Deep Learning? 代码&#xff1a;https://github.com/huawei-noah/AdderNet/tree/master 核心贡献 用filter与input feature之间的L1-范数距离作为“卷积层”的输出为了提升模型性能&#xff0c;提出全精度梯度…...

【TB作品】51单片机,具有报时报温功能的电子钟

2.具有报时报温功能的电子钟 一、功能要求: 1.显示室温。 2.具有实时时间显示。 3.具有实时年月日显示和校对功能。 4.具有整点语音播报时间和温度功能。 5.定闹功能,闹钟音乐可选。 6.操作简单、界面友好。 二、设计建议: 1.单片机自选(C51、STM32或其他单片机)。 2.时钟日历芯…...

了解C++工作机制

基于hello.cpp对C的运行进行一个初步认识&#xff0c;并介绍国外C大佬Cherno常用的项目结构和调试Tips C是如何工作的 C工作流程1.实用工程&#xff08;project&#xff09;结构&#xff08;1&#xff09;Microsoft Visual Studio2022新建项目后&#xff0c;自动生成的原始文件…...

力扣题目学习笔记(OC + Swift) 14. 最长公共前缀

14. 最长公共前缀 编写一个函数来查找字符串数组中的最长公共前缀。 如果不存在公共前缀&#xff0c;返回空字符串 “”。 方法一 竖向扫描法 个人感觉纵向扫描方式比较直观&#xff0c;符合人类理解方式&#xff0c;从前往后遍历所有字符串的每一列&#xff0c;比较相同列上的…...

WinSW设置应用程序开机启动

前言 由于使用windows自动的自启方法&#xff0c;不管是将程序启动服务放到开机自启文件夹中&#xff0c;还是创建任务计划程序&#xff0c;都没有很好的实现程序的开机自启效果&#xff0c;而WinSW很好的解决了这个问题。 下载 WinSW下载地址 注意&#xff1a;不同版本&#…...

Leetcode—96.不同的二叉搜索树【中等】

2023每日刷题&#xff08;六十四&#xff09; Leetcode—96.不同的二叉搜索树 算法思想 实现代码 class Solution { public:int numTrees(int n) {vector<int> G(n 1, 0);G[0] 1;G[1] 1;for(int i 2; i < n; i) {for(int j 1; j < i; j) {G[i] G[j - 1] * …...

正则表达式零宽断言

正则表达式零宽断言 工具类&#xff0c;正则表达式匹配文本内容正则表达式语法例子例子01零宽断言?< 不包含左边值? 不包含右边值例子 常用正则表达式校验数字的表达式校验字符的表达式 工具类&#xff0c;正则表达式匹配文本内容 /*** 正则表达式工具类*/ public class…...

uni-app学习记录

uni-app注意点记录 跳转到 tabBar 页面只能使用 switchTab 跳转路由API的目标页面必须是在pages.json里注册的vue页面。如果想打开web url&#xff0c;在App平台可以使用 plus.runtime.openURL或web-view组件&#xff1b;H5平台使用 window.open&#xff1b;小程序平台使用web…...

API资源对象StorageClass;Ceph存储;搭建Ceph集群;k8s使用ceph

API资源对象StorageClass;Ceph存储;搭建Ceph集群;k8s使用ceph API资源对象StorageClass SC的主要作用在于&#xff0c;自动创建PV&#xff0c;从而实现PVC按需自动绑定PV。 下面我们通过创建一个基于NFS的SC来演示SC的作用。 要想使用NFS的SC&#xff0c;还需要安装一个NFS…...

SpringBoot-17-MyBatis动态SQL标签之常用标签

文章目录 1 代码1.1 实体User.java1.2 接口UserMapper.java1.3 映射UserMapper.xml1.3.1 标签if1.3.2 标签if和where1.3.3 标签choose和when和otherwise1.4 UserController.java2 常用动态SQL标签2.1 标签set2.1.1 UserMapper.java2.1.2 UserMapper.xml2.1.3 UserController.ja…...

web vue 项目 Docker化部署

Web 项目 Docker 化部署详细教程 目录 Web 项目 Docker 化部署概述Dockerfile 详解 构建阶段生产阶段 构建和运行 Docker 镜像 1. Web 项目 Docker 化部署概述 Docker 化部署的主要步骤分为以下几个阶段&#xff1a; 构建阶段&#xff08;Build Stage&#xff09;&#xff1a…...

树莓派超全系列教程文档--(62)使用rpicam-app通过网络流式传输视频

使用rpicam-app通过网络流式传输视频 使用 rpicam-app 通过网络流式传输视频UDPTCPRTSPlibavGStreamerRTPlibcamerasrc GStreamer 元素 文章来源&#xff1a; http://raspberry.dns8844.cn/documentation 原文网址 使用 rpicam-app 通过网络流式传输视频 本节介绍来自 rpica…...

微软PowerBI考试 PL300-选择 Power BI 模型框架【附练习数据】

微软PowerBI考试 PL300-选择 Power BI 模型框架 20 多年来&#xff0c;Microsoft 持续对企业商业智能 (BI) 进行大量投资。 Azure Analysis Services (AAS) 和 SQL Server Analysis Services (SSAS) 基于无数企业使用的成熟的 BI 数据建模技术。 同样的技术也是 Power BI 数据…...

使用分级同态加密防御梯度泄漏

抽象 联邦学习 &#xff08;FL&#xff09; 支持跨分布式客户端进行协作模型训练&#xff0c;而无需共享原始数据&#xff0c;这使其成为在互联和自动驾驶汽车 &#xff08;CAV&#xff09; 等领域保护隐私的机器学习的一种很有前途的方法。然而&#xff0c;最近的研究表明&…...

《用户共鸣指数(E)驱动品牌大模型种草:如何抢占大模型搜索结果情感高地》

在注意力分散、内容高度同质化的时代&#xff0c;情感连接已成为品牌破圈的关键通道。我们在服务大量品牌客户的过程中发现&#xff0c;消费者对内容的“有感”程度&#xff0c;正日益成为影响品牌传播效率与转化率的核心变量。在生成式AI驱动的内容生成与推荐环境中&#xff0…...

Nuxt.js 中的路由配置详解

Nuxt.js 通过其内置的路由系统简化了应用的路由配置&#xff0c;使得开发者可以轻松地管理页面导航和 URL 结构。路由配置主要涉及页面组件的组织、动态路由的设置以及路由元信息的配置。 自动路由生成 Nuxt.js 会根据 pages 目录下的文件结构自动生成路由配置。每个文件都会对…...

学习STC51单片机31(芯片为STC89C52RCRC)OLED显示屏1

每日一言 生活的美好&#xff0c;总是藏在那些你咬牙坚持的日子里。 硬件&#xff1a;OLED 以后要用到OLED的时候找到这个文件 OLED的设备地址 SSD1306"SSD" 是品牌缩写&#xff0c;"1306" 是产品编号。 驱动 OLED 屏幕的 IIC 总线数据传输格式 示意图 …...

在Ubuntu中设置开机自动运行(sudo)指令的指南

在Ubuntu系统中&#xff0c;有时需要在系统启动时自动执行某些命令&#xff0c;特别是需要 sudo权限的指令。为了实现这一功能&#xff0c;可以使用多种方法&#xff0c;包括编写Systemd服务、配置 rc.local文件或使用 cron任务计划。本文将详细介绍这些方法&#xff0c;并提供…...

用docker来安装部署freeswitch记录

今天刚才测试一个callcenter的项目&#xff0c;所以尝试安装freeswitch 1、使用轩辕镜像 - 中国开发者首选的专业 Docker 镜像加速服务平台 编辑下面/etc/docker/daemon.json文件为 {"registry-mirrors": ["https://docker.xuanyuan.me"] }同时可以进入轩…...