如何在没有头文件的情况下调用动态库的类的私有成员函数

无头文件的动(静)态库的制作以及引用 Hello,大家好。近期项目组,在程序模块化设计时,不期望提供头文件。因此简单介绍一下无头文件的动(静)态库的创建以及使用。1.动态库的创建和使用创建    以windows系统,编译器Visual Studio为例.创建动态库工程dynamicLib:    编写demo代码(测试.cpp)如下:    #pragma once    #pragma execution_character_se... 阅读详情

如何在没有头文件的情况下调用动态库的类成员函数


源代码 https://github.com/TonyBeen/study/tree/master/dlopen

编写一个不存在虚函数的类
// class.h
#pragma once

class CClass
{
public:
    CClass();
    ~CClass();

private:
    void show();

private:
    char _buffer[64];
};

// class.cc
#include "class.h"
#include <stdio.h>
#include <string.h>

CClass::CClass()
{
    size_t size = sizeof(_buffer);
    memset(_buffer, '1', size);
    _buffer[size - 1] = '\0';
}

CClass::~CClass()
{
}

void CClass::show()
{
    printf("%s\n", _buffer);
}

extern "C" {
    CClass* createClass() {
        return new CClass();
    }

    void destroyClass(CClass* obj) {
        delete obj;
    }
}

编译指令: g++ -shared -fPIC -o libmyclass.so class.cc -O2

测试代码
// test_class.cc
#include <iostream>
#include <dlfcn.h>

typedef void* (*CreateFunction)();
typedef void (*DestroyFunction)(void *);

typedef void (*DoShow)(void *);

int main(int argc, char **argv)
{
    void* handle = dlopen("./libmyclass.so", RTLD_LAZY);
    if (!handle) {
        std::cerr << "Error opening shared library: " << dlerror() << std::endl;
        return 1;
    }

    // 获取创建和销毁函数的指针
    CreateFunction createFunc = (CreateFunction)dlsym(handle, "createClass");
    if (!createFunc) {
        std::cerr << "Error loading create function: " << dlerror() << std::endl;
        dlclose(handle);
        return 1;
    }

    DestroyFunction destroyFunc = (DestroyFunction)dlsym(handle, "destroyClass");
    if (!destroyFunc) {
        std::cerr << "Error loading destroy function: " << dlerror() << std::endl;
        dlclose(handle);
        return 1;
    }

    void* obj = createFunc();
    if (!obj) {
        std::cerr << "Error creating MyClass instance" << std::endl;
        dlclose(handle);
        return 1;
    }

    DoShow pFnShow = (DoShow)dlsym(handle, "_ZN6CClass4showEv");
    pFnShow(obj);

    destroyFunc(obj);

    // 关闭共享库
    dlclose(handle);

    return 0;
}

编译指令: g++ test_class.cc -o test_class -O2 -ldl

输出内容: 111111111111111111111111111111111111111111111111111111111111111

_ZN6CClass4showEv如何获取

获取方式有三种:
1、nm libmyclass.so

0000000000004058 b completed.7658
00000000000011c0 T createClass
w __cxa_finalize@@GLIBC_2.2.5
00000000000010a0 t deregister_tm_clones
0000000000001200 T destroyClass
0000000000001130 t __do_global_dtors_aux
0000000000003df8 d __do_global_dtors_aux_fini_array_entry
0000000000004048 d __dso_handle
0000000000004050 d DW.ref.__gxx_personality_v0
0000000000003e00 d _DYNAMIC
0000000000001224 t _fini
0000000000001170 t frame_dummy
0000000000003df0 d __frame_dummy_init_array_entry
0000000000002158 r FRAME_END
0000000000004000 d GLOBAL_OFFSET_TABLE
w gmon_start
0000000000002010 r __GNU_EH_FRAME_HDR
U __gxx_personality_v0@@CXXABI_1.3
0000000000001000 t _init
w _ITM_deregisterTMCloneTable
w _ITM_registerTMCloneTable
U puts@@GLIBC_2.2.5
00000000000010e0 t register_tm_clones
0000000000004058 d TMC_END
U _Unwind_Resume@@GCC_3.0
U _ZdlPvm@@CXXABI_1.3.9
00000000000011b0 T _ZN6CClass4showEv
0000000000001180 T _ZN6CClassC1Ev
0000000000001180 T _ZN6CClassC2Ev
00000000000011a0 T _ZN6CClassD1Ev
00000000000011a0 T _ZN6CClassD2Ev
U _Znwm@@GLIBCXX_3.4

2、readelf -s libmyclass.so

Symbol table ‘.dynsym’ contains 17 entries:
Num: Value Size Type Bind Vis Ndx Name
0: 0000000000000000 0 NOTYPE LOCAL DEFAULT UND
1: 0000000000000000 0 FUNC WEAK DEFAULT UND __cxa_finalize@GLIBC_2.2.5 (2)
2: 0000000000000000 0 FUNC GLOBAL DEFAULT UND _Znwm@GLIBCXX_3.4 (3)
3: 0000000000000000 0 FUNC GLOBAL DEFAULT UND _ZdlPvm@CXXABI_1.3.9 (4)
4: 0000000000000000 0 FUNC GLOBAL DEFAULT UND puts@GLIBC_2.2.5 (2)
5: 0000000000000000 0 FUNC GLOBAL DEFAULT UND __gxx_personality_v0@CXXABI_1.3 (5)
6: 0000000000000000 0 NOTYPE WEAK DEFAULT UND _ITM_deregisterTMCloneTab
7: 0000000000000000 0 FUNC GLOBAL DEFAULT UND _Unwind_Resume@GCC_3.0 (6)
8: 0000000000000000 0 NOTYPE WEAK DEFAULT UND gmon_start
9: 0000000000000000 0 NOTYPE WEAK DEFAULT UND _ITM_registerTMCloneTable
10: 0000000000001200 34 FUNC GLOBAL DEFAULT 12 destroyClass
11: 00000000000011c0 61 FUNC GLOBAL DEFAULT 12 createClass
12: 0000000000001180 28 FUNC GLOBAL DEFAULT 12 _ZN6CClassC2Ev
13: 00000000000011a0 2 FUNC GLOBAL DEFAULT 12 _ZN6CClassD1Ev
14: 00000000000011a0 2 FUNC GLOBAL DEFAULT 12 _ZN6CClassD2Ev
15: 0000000000001180 28 FUNC GLOBAL DEFAULT 12 _ZN6CClassC1Ev
16: 00000000000011b0 5 FUNC GLOBAL DEFAULT 12 _ZN6CClass4showEv

Symbol table ‘.symtab’ contains 62 entries:
Num: Value Size Type Bind Vis Ndx Name
0: 0000000000000000 0 NOTYPE LOCAL DEFAULT UND
1: 0000000000000238 0 SECTION LOCAL DEFAULT 1
2: 0000000000000260 0 SECTION LOCAL DEFAULT 2
3: 00000000000002a0 0 SECTION LOCAL DEFAULT 3
4: 0000000000000438 0 SECTION LOCAL DEFAULT 4
5: 000000000000058a 0 SECTION LOCAL DEFAULT 5
6: 00000000000005b0 0 SECTION LOCAL DEFAULT 6
7: 0000000000000630 0 SECTION LOCAL DEFAULT 7
8: 00000000000006f0 0 SECTION LOCAL DEFAULT 8
9: 0000000000001000 0 SECTION LOCAL DEFAULT 9
10: 0000000000001020 0 SECTION LOCAL DEFAULT 10
11: 0000000000001090 0 SECTION LOCAL DEFAULT 11
12: 00000000000010a0 0 SECTION LOCAL DEFAULT 12
13: 0000000000001224 0 SECTION LOCAL DEFAULT 13
14: 0000000000002000 0 SECTION LOCAL DEFAULT 14
15: 0000000000002010 0 SECTION LOCAL DEFAULT 15
16: 0000000000002058 0 SECTION LOCAL DEFAULT 16
17: 000000000000215c 0 SECTION LOCAL DEFAULT 17
18: 0000000000003df0 0 SECTION LOCAL DEFAULT 18
19: 0000000000003df8 0 SECTION LOCAL DEFAULT 19
20: 0000000000003e00 0 SECTION LOCAL DEFAULT 20
21: 0000000000003fe0 0 SECTION LOCAL DEFAULT 21
22: 0000000000004000 0 SECTION LOCAL DEFAULT 22
23: 0000000000004048 0 SECTION LOCAL DEFAULT 23
24: 0000000000004058 0 SECTION LOCAL DEFAULT 24
25: 0000000000000000 0 SECTION LOCAL DEFAULT 25
26: 0000000000000000 0 FILE LOCAL DEFAULT ABS crtstuff.c
27: 00000000000010a0 0 FUNC LOCAL DEFAULT 12 deregister_tm_clones
28: 00000000000010e0 0 FUNC LOCAL DEFAULT 12 register_tm_clones
29: 0000000000001130 0 FUNC LOCAL DEFAULT 12 __do_global_dtors_aux
30: 0000000000004058 1 OBJECT LOCAL DEFAULT 24 completed.7658
31: 0000000000003df8 0 OBJECT LOCAL DEFAULT 19 __do_global_dtors_aux_fin
32: 0000000000001170 0 FUNC LOCAL DEFAULT 12 frame_dummy
33: 0000000000003df0 0 OBJECT LOCAL DEFAULT 18 _frame_dummy_init_array
34: 0000000000000000 0 FILE LOCAL DEFAULT ABS class.cc
35: 0000000000000000 0 FILE LOCAL DEFAULT ABS crtstuff.c
36: 0000000000002158 0 OBJECT LOCAL DEFAULT 16 FRAME_END
37: 0000000000000000 0 FILE LOCAL DEFAULT ABS
38: 0000000000002010 0 NOTYPE LOCAL DEFAULT 15 __GNU_EH_FRAME_HDR
39: 0000000000004048 0 OBJECT LOCAL DEFAULT 23 __dso_handle
40: 0000000000004050 8 OBJECT LOCAL DEFAULT 23 DW.ref._gxx_personality
41: 0000000000001224 0 FUNC LOCAL DEFAULT 13 _fini
42: 0000000000001000 0 FUNC LOCAL DEFAULT 9 _init
43: 0000000000003e00 0 OBJECT LOCAL DEFAULT 20 _DYNAMIC
44: 0000000000004058 0 OBJECT LOCAL DEFAULT 23 TMC_END
45: 0000000000004000 0 OBJECT LOCAL DEFAULT 22 GLOBAL_OFFSET_TABLE
46: 00000000000011c0 61 FUNC GLOBAL DEFAULT 12 createClass
47: 0000000000000000 0 FUNC WEAK DEFAULT UND __cxa_finalize@@GLIBC_2.2
48: 0000000000001180 28 FUNC GLOBAL DEFAULT 12 _ZN6CClassC2Ev
49: 00000000000011a0 2 FUNC GLOBAL DEFAULT 12 _ZN6CClassD1Ev
50: 00000000000011b0 5 FUNC GLOBAL DEFAULT 12 _ZN6CClass4showEv
51: 00000000000011a0 2 FUNC GLOBAL DEFAULT 12 _ZN6CClassD2Ev
52: 0000000000000000 0 FUNC GLOBAL DEFAULT UND _Znwm@@GLIBCXX_3.4
53: 0000000000000000 0 FUNC GLOBAL DEFAULT UND _ZdlPvm@@CXXABI_1.3.9
54: 0000000000001180 28 FUNC GLOBAL DEFAULT 12 _ZN6CClassC1Ev
55: 0000000000000000 0 FUNC GLOBAL DEFAULT UND puts@@GLIBC_2.2.5
56: 0000000000000000 0 FUNC GLOBAL DEFAULT UND __gxx_personality_v0@@CXX
57: 0000000000001200 34 FUNC GLOBAL DEFAULT 12 destroyClass
58: 0000000000000000 0 NOTYPE WEAK DEFAULT UND _ITM_deregisterTMCloneTab
59: 0000000000000000 0 FUNC GLOBAL DEFAULT UND _Unwind_Resume@@GCC_3.0
60: 0000000000000000 0 NOTYPE WEAK DEFAULT UND gmon_start
61: 0000000000000000 0 NOTYPE WEAK DEFAULT UND _ITM_registerTMCloneTable

3、objdump -x libmyclass.so
此处输出过多, 不在展示

通过以上方式均可获取到符号表
只需要找到_ZN6CClass4showEv即可

调用

普通函数的调用方式为直接调用,如createClass。
类的成员函数调用:

class T
{
public:
	void print();
};

T t = new T();
auto pFnPrint = &T::print;
(t->*pFnPrint)();

然这么写在编译时确实没问题,但是动态加载的情况下又没有类的头文件,则无法这么写,因为无法确定函数的地址。
所以需要使用dlsym获取到地址,但是g++在编译时会对函数名称进行修改,如上所示。故传递时需要传修改后的名字。
另一方面,类的成员函数即使在书写时无参,那么编译后其实也存在参数的,即类的this。
所以在生命函数时将其声明为typedef void (*DoShow)(void *);调用也就和普通函数一致。

注意:以上不涉及虚函数时可正常使用,当存在虚函数时,会存在虚函数表,无法确定被调用函数真正的地址。

如何用VS2019创建并调用动态库 网上查了相关资料,创建动态库主要有两种方式,一种是通过空项目创建动态库,一种是直接创建动态链接库,本文所总结的就是第二种,直接创建动态链接库。 阅读详情

相关推荐

QT动态库实现及调用方式

QT动态库实现及调用方式,源码工程和库文件,简单的实现方便了解QT动态库的嗲用方式

c/c++开发时直接调用dll动态库中的函数,无需使用头文件编译

可以实现windows下的exe直接加载dll动态库,实现exe的动态扩展

qq_43013686的博客 4112

使用cubeMX生成USB HID设备

本文主要介绍如何使用stm32开发板和cubeMX生成HID设备,供参考。

专注音频,高效工作,快乐生活! 970

查看某个二进制可执行文件的编译器版本

使用命令strings: [~/projects]$ strings libmyproject.so | grep GCC GCC_3.0 GCC: (GNU) 5.5.0 _Unwind_Resume@@GCC_3.0 上面的结果表示,编译出文件libmyproject.so的编译器版本是GCC 5.5.0 参考链接 STRINGS(1) GNU Development Tools S...

Learning 5070

【CVPR 2025】低光增强HVI论文精读与源码复现---part1 论文网络精读

【CVPR 2025】本文参考论文HVI: A New Color Space for Low-light Image Enhancement part1 在文章中对论文核心网络与原理展开详细解释 part2 对论文公开代码的arch网络与其他核心部分展开详细解释

BOB_BOB_BOB_的博客 3257

新手必看:用FileZilla从武大IGS中心下载GNSS数据,再到crx2rnx转换的完整流程

本文详细介绍了新手如何通过FileZilla从武汉大学IGS中心下载GNSS数据,并使用crx2rnx工具将数据转换为RINEX格式的完整流程。涵盖工具准备、FTP连接、文件解压、格式转换及常见问题排查,帮助测绘和地信专业人员高效处理GNSS观测值数据。

weixin_29292431的博客 424

C语言函数未声明在头文件中,任然可以调用

C语言函数未声明在头文件中,任然可以调用

weixin_40751444的博客 836

从GAN生成失败案例出发:为什么你的AI画不准位置?CoordConv保姆级解决方案

本文深入探讨了GAN生成图像时位置偏移问题的根源,并提供了CoordConv的保姆级解决方案。通过分析传统CNN在空间坐标建模上的缺陷,详细介绍了CoordConv的原理、实现步骤及在StyleGAN2等模型中的实战应用,显著提升了医学图像生成等任务的定位精度。

pp12345的博客 204

如何在Java中调用DLL动态库

调用DLL动态库为Java程序带来了更多可能性。尽管处理本地代码有一定的复杂性,JNI和JNA提供了桥接Java与本地代码的有效方法。通过以上示例,希望你能够对如何在Java中加载和调用DLL库有一个清晰的理解,并能成功集成到你的应用程序中。

恋上、小幸福的博客 6034

WIFI 相关的频偏调试以及天线调试记录

WIFI RF 相关的频偏调试以及天线调试 1,频率误差(Frequency Error) 频率误差(Frequency Error):表征射频信号偏离该信号所处信道中心频率的大小,单位PPM。频偏误差要求范围如下表。 频偏越小越好。PPM的计算公式如下: 问题: 我们ESP8089认证测试的时候频偏测试超了。需要修改哪些呢。 测试频率点在2.411865385GHz 宣称点:2.412GHz 频率偏移计算:{(2.412GHz-2.411865385GHz)÷2...

armkits的博客 1万+

Unreal5从入门到精通之EnhancedInput增强输入系统详解

从Unreal5开始,老版的输入系统,正式替换为EnhancedInput增强型输入系统,他们之间有什么区别呢?如果有使用过Unity的同学,大概也知道,Unity也在2020版本之后逐渐把输入系统也升级成了新版输入系统,为什么Unreal和Unity都热衷于升级输入系统呢?这之间又有什么联系呢?官方:增强输入EnhancedInput希望这篇文章能够对你有所帮助。

TxNet 944

Qt5建立动态库及调用

Qt5建立动态库及调用Qt5建立动态库Qt5调用动态库 Qt5建立动态库 Step1:点击工具栏 " 文件 ” →点击项目中列表的" Libaray" →点击右侧” C++库“ Step2:类型选择“共享库”,名称自定义(示例名称为“TestDLL1”),路径自定义。 Step3:选择自己需要的编译器。 Step4:选择依赖项,这边可以根据自己的需求来选择动态库中需要使用到的Qt模块。本文做一个简...

CarbonPie 3182

YOLOv11改进策略【卷积层】| 引入注意力卷积模块RFAConv,关注感受野空间特征 助力yolov11精度提升

RFAConv:创新空间注意力和标准卷积运算感受野空间特征是针对卷积核设计的,根据卷积核大小动态生成。以3×3卷积核为例,它由非重叠滑动窗口组成,每个窗口代表一个感受野滑块。

Limiiiing的博客 1821

动态调用动态库的方法

登录 | 注册 罗马非一日建成 能成功的人多少都有一份坚持~~ 目录视图摘要视图订阅   动态调用动态库方法 | from web 标签: dll编译器classwinapilibrarynull 2011-11-10 21:01 684人阅

wei_qifan的博客 3407

BES2700的PMU

BES2700ZP-BES2700芯片的PMU架构分析摘要:本文档分析了BES2700芯片的电源管理单元(PMU)架构。实际应用中仅需为VBAT引脚供电,其余电源均由芯片内部PMU提供。文档包含架构示意图、问题列表和参考链接,涉及PMU工作原理、外部供电要求等关键技术点。待解决问题包括具体供电参数和内部电源转换机制等。通过添加日志信息和代码片段,为开发人员提供了调试PMU功能的实用方法。

云淡风轻 117

LinePhone3.2.7(android端最新版本) sip客户端

SIP客户端For android:LinePhone3.2.7(最新版本),官网地址:http://www.linphone.org/

《C++避坑神器·十五》动态库只有dll文件,没有.lib文件时动态调用dll的中类和成员函数

换句话说,如果应用程序决定要调用 DLL 中的函数,则可以将 DLL 显式加载到进程的地址空间中,获取 DLL 中包含的函数的虚拟内存地址,然后使用此内存地址调用函数。该列表包含成员函数Add、Sub和构造函数calculate的虚拟内存地址,1,3,5后面一串乱码实际是构造函数,Add,Sub对应的函数名称,现在我们要用def文件来修正它。我们在自己的项目中新建一个“calculate.def”文件,并在“工程->设置->Link”中添加参数(/def:“.\calculate.def”),并编。

cs1395293598的博客 4040

Statistics and Machine Learning Toolbox

Statistics and Machine Learning Toolbox(带书签),MATLAB统计学习工具

C++项目调用动态库dll函数

日常开发中C++项目调用动态库函数

weixin_43016824的博客 3633

win10 跳过U8环境检测的IE WebControls.rar

win10 安装u8的时候 提示IE WebControls 不通过,这个工具可以欺骗u8的检查。 跳过U8环境检测的IE WebControls。提示导入失败后,重新检测通过。

文档:亲测可用解决vnc灰屏,黑屏,鼠标大黑叉情况

主要解决vnc-viewer灰屏,黑屏,鼠标大黑叉等现象,详细见文档。

C语言调用so动态库的两种方式

方式1:类似静态库的调用(使用头文件) 这种方式生成的程序会在启动时候就加载so动态库。 add.h int add(int x, int y); add.c #include "add.h" int add(int x, int y) { return (x + y); } main.c #include <stdio.h> #include "add.h" int main() { int sum = add(7, 8); printf("7+

团长的专栏 4831

使用静态库动态库也要头文件

包含头文件:始终需要包含,因为它是 QCustomPlot 类的声明。动态库和导入库:使用动态库(.dll文件)和导入库(.lib文件)时,不需要包含文件。正确设置项目:确保头文件路径、导入库路径和动态库路径正确配置。通过以上设置,你可以顺利使用 QCustomPlot 的动态库来绘制波形图。

轩辕霸天L 1029

虚函数与动态库函数的调用冲突:缺失实现下的多态行为分析

②当一个 h头文件有对应的 cpp源文件,且 h头文件中声明了与 zemotion.dll 动态库文件中的 setXYPosition 函数的同名函数,且对应的 cpp源文件中同样有 setXYPosition 函数的具体实现。③但如果在②条件下,在 cpp源文件中的 setXYPosition 函数下又写了一个 ::setXYPosition,则此时若程序运行到此处时,程序实际上调用的会是 zemotion.dll 动态库文件中的 setXYPosition 函数!时,将实际执行派生类的实现。

weixin_44936096的博客 365

C和C++互相调用动态库

平时需要接触c和c++,有时会遇到两种语言互相调用动态库的情况,这时就要对代码进行一些处理,做个记录。 前提 两种语言生成的库是无法直接互相调用的,原因在于c++支持重载,因此存在改名机制(也可能是因为有改名机制所以支持重载 ==!)_,即生成的中间文件会对函数名进行改写,会将函数名与参数列表相结合生产新的函数名,这样就可以通过不同的函数名来区分重载函数了。 而C语言没有改名机制,函数名未改动,若两种语言直接调用,便会报错:函数名未定义。 eg: C++代码 ,cplus.cpp 和 cplus.h #in

一起学习一起进步~ 2066

dll动态库生成与调用(1):生成dll动态库、C程序调用动态库

文章目录文件目录结构一、动态库的生成1.新建项目,用于生成dll库2.编写动态库的.h头文件、.c源文件3.生成动态库文件二、在C语言程序中调用dll动态库1.第一种调用方法:仅配置dll文件路径(“显示链接”)2.第二种调用方法:配置.h,lib,dll文件路径三、JNA调用动态库四、JNI调用动态库五、附加内容1. 错误记录1.1 LNK2019 LNK1120 无法解析的外部符号 “xxxx...

Stone Ocean 1696

C#调用C++动态库

在C#开发过程中,我们可能会遇到需要调用Windows API 或是第三方库的场景,然而有时候这些库是由C++编写的,并不能直接应用在C#的程序中,这为开发带来许多阻力。本文介绍两种使用C#调用C++动态库的方式,以及在这个过程中可能遇到的问题,看完之后会对你的困境有所帮助。

weixin_44445770的博客 6171

C语言中静态库函数和动态库函数的创建以及调用

C语言中调用动态库函数的两种方式 方式一.隐式调用 将动态库的相关文件拷贝到当前目录下(lib、dll),然后添加以下代码,在程序中指定连接库函数。 注意:第二个参数给出的是引入库文件(或称“导出库文件”),而不是dll。在程序运行过程中,lib将dll中需要用到的函数映射到对应的内存空间。 #pragma comment(lib, "./mydll.lib") 方式二.显示调用 ...

Hello_MyDream的博客 3万+

VS开发C++动态库及其调用程序

用VS建立一个解决方案,包括两个项目:动态库TestDll和应用程序TestExe。以下详细介绍TestDll动态库配置导出类和函数的方法,以及TestExe应用程序如何调用TestDll和配置项目依赖关系。

咸鱼爱幻想的博客 2881
上一篇: libiconv转码
下一篇: 纤程与协程以及有栈协程和无栈协程的区别
山有木兮啊
博客等级 码龄8年 135粉丝 132原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值