C动态库的生成与在Python和QT中的调用方法

news/2025/2/1 20:49:13/

目录

一、动态库生成

1)C语言生成动态库

 2)c++类生成动态库

 二、动态库调用

1)Python调用DLL

2)QT调用DLL

三、存在的一些问题

python%E8%B0%83%E7%94%A8%E5%B0%81%E8%A3%85%E4%BA%86%E7%B1%BB%E7%9A%84DLL%E5%8F%AF%E8%83%BD%E8%B0%83%E7%94%A8%E4%B8%8D%E6%88%90%E5%8A%9F-toc" name="tableOfContents" style="margin-left:40px">1)python调用封装了类的DLL可能调用不成功

2)DLL格式不匹配的问题

四、总结


动态库文件在程序开发中运用很常见,但C和C++代码生成动态库文件,以及在使用时均存在一些差异,本文对两者的差异进行了讲解,并通过具体的实例加以说明。实例均在Windows系统下进行,Linux系统下的实现一样。

一、动态库生成

1)C语言生成动态库

我们直接新建一个记事本文件,在文件中输入如下代码。写一个简单的加法函数,函数返回相加的结果,然后将记事本文件保存为myC.c文件,名称随意,扩展名为c。

#include<stdio.h>int add(int a, int b)
{
return a+b;
}

然后使用win+r键 ,输入“cmd”打开命令窗口,使用cd /d E:\Tem,将工作目录切换到myC.c文件存放的E:\Tem路径下。如下图所示。

然后在命令行中输入:"gcc -shared -o myC.dll myC.c" ,执行该命令就可以在当前路径下得到动态库文件myC.dll。

 2)c++类生成动态库

C++是面向对象的编程语言,代码文件一般包含.h头文件和.cpp文件。此处使用记事本分别新建两个文件,命名为myclass.h和myclass.cpp。在文件中输入以下代码,实现用一个整数创建一个类,将整数赋给成员变量,并可改变和返回该成员变量的值。

//头文件
// myclass.h
#ifndef MYCLASS_H
#define MYCLASS_H#ifdef BUILD_MYDLL
#define MYDLL_API __declspec(dllexport)
#else
#define MYDLL_API __declspec(dllimport)
#endifclass MYDLL_API MyClass {
private:int value;
public:MyClass(int val);~MyClass();int getValue();void setValue(int val);
};// 封装 C 风格的接口函数
extern "C" {MYDLL_API MyClass* CreateMyClass(int val);MYDLL_API int GetValue(MyClass* obj);MYDLL_API void SetValue(MyClass* obj, int val);MYDLL_API void DestroyMyClass(MyClass* obj);
}#endif
//cpp文件
// myclass.cpp
#include "myclass.h"MyClass::MyClass(int val) : value(val) {}MyClass::~MyClass() {}int MyClass::getValue() {return value;
}void MyClass::setValue(int val) {value = val;
}extern "C" {MYDLL_API MyClass* CreateMyClass(int val) {return new MyClass(val);}MYDLL_API int GetValue(MyClass* obj) {return obj->getValue();}MYDLL_API void SetValue(MyClass* obj, int val) {obj->setValue(val);}MYDLL_API void DestroyMyClass(MyClass* obj) {delete obj;}
}

 在命令窗口中执行命令“g++ -shared -o myclass.dll -DBUILD_MYDLL myclass.cpp -Wl,--out-implib=libmyclass.a”,可以得到编译完成后的dll文件。

  • -shared:指定生成共享库(DLL)。

  • -o myclass.dll:指定输出的 DLL 文件名。

  • -DBUILD_MYDLL:定义宏,使 MYDLL_API 被定义为 __declspec(dllexport),用于导出函数和类。

  • -Wl,--out-implib=libmyclass.a:生成导入库文件。

 二、动态库调用

1)Python调用DLL

ctypes是 Python 标准库中的一个外部函数库,它提供了与 C 语言兼容的数据类型,允许调用动态链接库(DLL)中的函数。在python中具体实现代码如下,程序运行时需要将生成的myC.dll动态库复制到当前python程序文件所在路径下,否则需要在下面文件路径中使用绝对路径。

python">import ctypes# 加载 myC.dll
dll = ctypes.CDLL("./myC.dll")
dll.add.argtypes = [ctypes.c_int, ctypes.c_int]  # 定义函数参数和返回值类型
dll.add.restype = ctypes.c_int
a = dll.add(2, 11)
print(a)
print('--------------------')

2)QT调用DLL

QT调用DLL有动态和静态两种方式。

(1)动态调用

动态调用需要使用到QT的QLibrary类,此处以调用C++生成的动态库为例,具体代码如下。使用QLibrary类时,只需要在代码中用QLibrary类加载相应的DLL文件,并通过定义函数指针的方式取出需要使用的DLL函数。

在此例中,调用DLL中的函数时,首先需要使用DLL中的创建对象函数创建一个类的实例,由于在调用时不能知道DLL类的结构,因此采用QObject *来接收创建对象的指针。

python">#include <QCoreApplication>
#include <QLibrary>
#include <QDebug>
#include <QObject>int main(int argc, char *argv[])
{QCoreApplication a(argc, argv);QLibrary myLib("E:/Tem/useDLL/myclass.dll");if (myLib.load()) {// 定义函数指针类型typedef QObject* (*creatFunction)(int);creatFunction create = (creatFunction)myLib.resolve("CreateMyClass");if (create) {// 调用函数QObject* obj = create(3);//创建对象typedef int (*getFunction)(QObject*);getFunction get = (getFunction)myLib.resolve("GetValue");int val = get(obj);qDebug() << "The get is:" << val;typedef void (*setFunction)(QObject*,int);setFunction set = (setFunction)myLib.resolve("SetValue");set(obj,100);val = get(obj);qDebug() << "The set is:" << val;typedef void (*desFunction)(QObject*);desFunction des = (desFunction)myLib.resolve("DestroyMyClass");des(obj);qDebug() << "obj has been deleted.";} else {qDebug() << "Failed to resolve the function.";}}return a.exec();
}

上述代码执行结果:

 (2)静态调用DLL

当使用静态调用方法时,需要将生成的DLL动态库和对应的.h头文件拷贝到工程目录下。然后在工程的.pro文件中添加代码“LIBS += -L../ -lmyclass”,在.cpp文件中包含DLL的头文件,然后就可以正常使用DLL了。具体实现代码如下。

#include <QCoreApplication>
#include "myclass.h"  //包含DDL的头文件
//#include <QLibrary>
#include <QDebug>
#include <QObject>int main(int argc, char *argv[])
{QCoreApplication a(argc, argv);MyClass my(3);qDebug()<<my.getValue();my.setValue(5);qDebug()<<my.getValue();return a.exec();
}

 上述程序输出结果为:

三、存在的一些问题

python%E8%B0%83%E7%94%A8%E5%B0%81%E8%A3%85%E4%BA%86%E7%B1%BB%E7%9A%84DLL%E5%8F%AF%E8%83%BD%E8%B0%83%E7%94%A8%E4%B8%8D%E6%88%90%E5%8A%9F" name="1%EF%BC%89python%E8%B0%83%E7%94%A8%E5%B0%81%E8%A3%85%E4%BA%86%E7%B1%BB%E7%9A%84DLL%E5%8F%AF%E8%83%BD%E8%B0%83%E7%94%A8%E4%B8%8D%E6%88%90%E5%8A%9F">1)python调用封装了类的DLL可能调用不成功

从DLL的生成可知,c和c++代码生成DLL在代码实现上是不一样的,c++代码需要使用到 extern "C"和“__declspec(dllexport)”。在使用python调用封装了c++类的动态库时,会出现ctypes.CDLL()加载动态库文件不成功的情况,经过测试发现是因为在DLL的函数中使用了new关键字实例化对象造成的,但是具体的原因不清楚。若改用直接申明对象的方式,将对象的指针返回,但是在python中传递该指针后调用函数时会存在访问非法,或访问不到类中变量问题。而同样的DLL文件在QT中调用是完全没有问题的。

2)DLL格式不匹配的问题

在调用DLL时可能存在格式不匹配的问题,这个可能是因为使用的gcc编译器版本不同,或者32位与64位不兼容的原因。应确保DLL库的编译工具与调用它的程序使用相同的gcc,避免兼容性问题。一些比较常用的64位gcc版本可以在这里下载。

四、总结

DLL动态库方便程序模块化开发,但是在进行跨语言调用时,最好只在DLL中封装相应的实现函数,而不要跨语言调用类的实现,避免一些不可预测的问题。


http://www.ppmy.cn/news/1568510.html

相关文章

每日一博 - 三高系统架构设计:高性能、高并发、高可用性解析

文章目录 引言一、高性能篇1.1 高性能的核心意义 1.2 影响系统性能的因素1.3 高性能优化方法论1.3.1 读优化&#xff1a;缓存与数据库的结合1.3.2 写优化&#xff1a;异步化处理 1.4 高性能优化实践1.4.1 本地缓存 vs 分布式缓存1.4.2 数据库优化 二、高并发篇2.1 高并发的核心…

图形编辑器基于Paper.js教程22:在图形矢量编辑器中,实现两个元素的差集,交集,并集,切割

在图形编辑器中&#xff0c;我们有时需要这样的一个图形&#xff0c; 或者这样的一个图形 像这种图形其实是基于相交的圆和矩形进行计算得出来的&#xff0c;这种操作大家一般叫做图形的布尔操作。 本片文章就教大家如何在图形编辑器中&#xff0c;实现 两个元素的差集&#…

使用Pygame制作“俄罗斯方块”游戏

1. 前言 俄罗斯方块&#xff08;Tetris&#xff09; 是一款由方块下落、行消除等核心规则构成的经典益智游戏&#xff1a; 每次从屏幕顶部出现一个随机的方块&#xff08;由若干小方格组成&#xff09;&#xff0c;玩家可以左右移动或旋转该方块&#xff0c;让它合适地堆叠在…

一文讲解JVM中的G1垃圾收集器

接上一篇博文&#xff0c;这篇博文讲下JVM中的G1垃圾收集器 G1在JDK1.7时引入&#xff0c;在JDK9时取代了CMS成为默认的垃圾收集器&#xff1b; G1把Java堆划分为多个大小相等的独立区域Region&#xff0c;每个区域都可以扮演新生代&#xff08;Eden和Survivor&#xff09;或老…

消息队列篇--通信协议篇--STOMP(STOMP特点、格式及示例,WebSocket上使用STOMP,消息队列上使用STOMP等)

STOMP&#xff08;Simple Text Oriented Messaging Protocol&#xff0c;简单面向文本的消息传递协议&#xff09;是一种轻量级、基于文本的协议&#xff0c;旨在为消息代理&#xff08;消息队列&#xff09;和客户端之间的通信&#xff08;websocket&#xff09;提供一种简单的…

Clock Controller of RH850/F1KH-D8, RH850/F1KM-S4, RH850/F1KM-S2

&esmp; 时钟控制器由时钟振荡电路、时钟选择电路、和时钟输出电路组成。   RH850/F1KH、RH850/F1KM单片机的时钟控制器具有以下特点: 六个片上时钟振荡器: 主振荡器(MainOSC),振荡频率分别为8、16、20和24 MHz子振荡器(SubOSC),振荡频率为32.768 kHz*1 100针的产品…

【浏览器 - Mac实时调试iOS手机浏览器页面】

最近开发个项目&#xff0c;需要在 Mac 电脑上调试 iOS 手机设备上的 Chrome 浏览器&#xff0c;并查看Chrome网页上的 console 信息&#xff0c;本来以为要安装一些插件&#xff0c;没想到直接使用Mac上的Safari 直接可以调试&#xff0c;再此记录下&#xff0c;分享给需要的伙…

基础项目实战——3D赛车(c++)

目录 前言一、渲染引擎二、关闭事件三、梯形绘制四、轨道绘制五、边缘绘制六、草坪绘制七、前后移动八、左右移动​九、曲线轨道​十、课山坡轨道​十一、循环轨道​十二、背景展示​十三、引入速度​十四、物品绘制​十五、课数字路障​十六、分数展示​十七、重新生成​十八、…