C动态库的生成与在Python和QT中的调用方法
目录
一、动态库生成
1)C语言生成动态库
2)c++类生成动态库
二、动态库调用
1)Python调用DLL
2)QT调用DLL
三、存在的一些问题
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程序文件所在路径下,否则需要在下面文件路径中使用绝对路径。
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 *来接收创建对象的指针。
#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();
}
上述程序输出结果为:
![]()
三、存在的一些问题
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中封装相应的实现函数,而不要跨语言调用类的实现,避免一些不可预测的问题。
相关文章:
C动态库的生成与在Python和QT中的调用方法
目录 一、动态库生成 1)C语言生成动态库 2)c类生成动态库 二、动态库调用 1)Python调用DLL 2)QT调用DLL 三、存在的一些问题 1)python调用封装了类的DLL可能调用不成功 2)DLL格式不匹配的问题 四、…...
C++ Primer 自定义数据结构
欢迎阅读我的 【CPrimer】专栏 专栏简介:本专栏主要面向C初学者,解释C的一些基本概念和基础语言特性,涉及C标准库的用法,面向对象特性,泛型特性高级用法。通过使用标准库中定义的抽象设施,使你更加适应高级…...
解析 Oracle 中的 ALL_SYNONYMS 和 ALL_VIEWS 视图:查找同义词与视图的基础操作
目录 前言1. ALL_SYNONYMS 视图2. ALL_VIEWS 视图3. 扩展 前言 🤟 找工作,来万码优才:👉 #小程序://万码优才/r6rqmzDaXpYkJZF 1. ALL_SYNONYMS 视图 在 Oracle 数据库中,同义词(Synonym)是对数…...
PyTorch框架——基于深度学习YOLOv8神经网络学生课堂行为检测识别系统
基于YOLOv8深度学习的学生课堂行为检测识别系统,其能识别三种学生课堂行为:names: [举手, 读书, 写字] 具体图片见如下: 第一步:YOLOv8介绍 YOLOv8 是 ultralytics 公司在 2023 年 1月 10 号开源的 YOLOv5 的下一个重大更新版本…...
深入探索 Vue 3 Markdown 编辑器:高级功能与实现
目录 1. 为什么选择 Markdown 编辑器?2. 选择合适的 Markdown 编辑器3. 安装与基本配置安装 配置 Markdown 编辑器代码说明 4. 高级功能实现4.1 实时预览与双向绑定4.2 插入图片和图像上传安装图像上传插件配置图像上传插件 4.3 数学公式支持安装 KaTeX配置 KaTeX 插…...
7.攻防世界fileclude
题目描述 进入题目页面如下 看到题目提示应该为文件包含漏洞 解释上述代码 // 输出提示信息:错误的方式! WRONG WAY! <?php // 包含名为 "flag.php" 的文件,通常这个文件里可能包含重要的敏感信息,如 flag inclu…...
【自然语言处理(NLP)】深度学习架构:Transformer 原理及代码实现
文章目录 介绍Transformer核心组件架构图编码器(Encoder)解码器(Decoder) 优点应用代码实现导包基于位置的前馈网络残差连接后进行层规范化编码器 Block编码器解码器 Block解码器训练预测 个人主页:道友老李 欢迎加入社…...
【HarmonyOS之旅】基于ArkTS开发(三) -> 兼容JS的类Web开发(二)
目录 1 -> HML语法 1.1 -> 页面结构 1.2 -> 数据绑定 1.3 -> 普通事件绑定 1.4 -> 冒泡事件绑定5 1.5 -> 捕获事件绑定5 1.6 -> 列表渲染 1.7 -> 条件渲染 1.8 -> 逻辑控制块 1.9 -> 模板引用 2 -> CSS语法 2.1 -> 尺寸单位 …...
当WebGIS遇到智慧文旅-以长沙市不绕路旅游攻略为例
目录 前言 一、旅游数据组织 1、旅游景点信息 2、路线时间推荐 二、WebGIS可视化实现 1、态势标绘实现 2、相关位置展示 三、成果展示 1、第一天旅游路线 2、第二天旅游路线 3、第三天旅游路线 4、交通、订票、住宿指南 四、总结 前言 随着信息技术的飞速发展&…...
《大数据时代“快刀”:Flink实时数据处理框架优势全解析》
在数字化浪潮中,数据呈爆发式增长,实时数据处理的重要性愈发凸显。从金融交易的实时风险监控,到电商平台的用户行为分析,各行业都急需能快速处理海量数据的工具。Flink作为一款开源的分布式流处理框架,在这一领域崭露头…...
【机器学习理论】朴素贝叶斯网络
基础知识: 先验概率:对某个事件发生的概率的估计。可以是基于历史数据的估计,可以由专家知识得出等等。一般是单独事件概率。 后验概率:指某件事已经发生,计算事情发生是由某个因素引起的概率。一般是一个条件概率。 …...
使用Pygame制作“吃豆人”游戏
本篇博客展示如何使用 Python Pygame 编写一个简易版的“吃豆人(Pac-Man)” 风格游戏。这里我们暂且命名为 Py-Man。玩家需要控制主角在一个网格地图里移动、吃掉散布在各处的豆子,并躲避在地图中巡逻的幽灵。此示例可帮助你理解网格地图、角…...
使用 Docker(Podman) 部署 MongoDB 数据库及使用详解
在现代开发环境中,容器化技术(如 Docker 和 Podman)已成为部署和管理应用程序的标准方式。本文将详细介绍如何使用 Podman/Docker 部署 MongoDB 数据库,并确保其他应用程序容器能够通过 Docker 网络成功连接到 MongoDB。我们将逐步…...
SQL入门到精通 理论+实战 -- 在 MySQL 中学习SQL语言
目录 一、环境准备 1、MySQL 8.0 和 Navicat 下载安装 2、准备好的表和数据文件: 二、SQL语言简述 1、数据库基础概念 2、什么是SQL 3、SQL的分类 4、SQL通用语法 三、DDL(Data Definition Language):数据定义语言 1、操…...
Electricity Market Optimization 探索系列(一)
本文参考链接:Linear Programming Mini Example 先从一个线性规划的例子说起: 问题背景: 现在需要使用两台发电机满足用户的用电需求,发电机一的发电功率上限是 6MW,发电机二的发电功率上限是 4MW,发电…...
x86-64数据传输指令
关于汇编语言一些基础概念的更详细的介绍,可移步MIPS指令集(一)基本操作_mips指令 sw-CSDN博客 该指令集中一个字2字节。 该架构有16个64位寄存器,名字都以%r开头,每个寄存器的最低位字节,低1~2位字节&…...
【ESP32】ESP-IDF开发 | WiFi开发 | TCP传输控制协议 + TCP服务器和客户端例程
1. 简介 TCP(Transmission Control Protocol),全称传输控制协议。它的特点有以下几点:面向连接,每一个TCP连接只能是点对点的(一对一);提供可靠交付服务;提供全双工通信&…...
算法基础学习——快排与归并(附带java模版)
快速排序和归并排序是两种速度较快的排序方式,是最应该掌握的两种排序算法, (一)快速排序(不稳定的) 基本思想:分治 平均时间复杂度:O(nlogn) / 最慢O(n^2) / 最快O(n) 步骤&…...
指针的进化—sizeof和strlen对比(字符串和字符数组的区分)
1.前言 如果你对各个数组的内容存放是什么没有个清晰的概念,对指针偏移之后的数量算不出来或者模棱两可,那么本篇就来详细介绍sizeof和strlen来具象化的显示数组的内容存放了多少内容,偏移量变化后的变化,这个数组进行运算后会不会…...
TensorFlow简单的线性回归任务
如何使用 TensorFlow 和 Keras 创建、训练并进行预测 1. 数据准备与预处理 2. 构建模型 3. 编译模型 4. 训练模型 5. 评估模型 6. 模型应用与预测 7. 保存与加载模型 8.完整代码 1. 数据准备与预处理 我们将使用一个简单的线性回归问题,其中输入特征 x 和标…...
【memgpt】letta 课程1/2:从头实现一个自我编辑、记忆和多步骤推理的代理
llms-as-operating-systems-agent-memory llms-as-operating-systems-agent-memory内存 操作系统的内存管理...
6-图像金字塔与轮廓检测
文章目录 6.图像金字塔与轮廓检测(1)图像金字塔定义(2)金字塔制作方法(3)轮廓检测方法(4)轮廓特征与近似(5)模板匹配方法6.图像金字塔与轮廓检测 (1)图像金字塔定义 高斯金字塔拉普拉斯金字塔 高斯金字塔:向下采样方法(缩小) 高斯金字塔:向上采样方法(放大)…...
深入理解Java引用传递
先看一段代码: public static void add(String a) {a "new";System.out.println("add: " a); // 输出内容:add: new}public static void main(String[] args) {String a null;add(a);System.out.println("main: " a);…...
925.长按键入
目录 一、题目二、思路三、解法四、收获 一、题目 你的朋友正在使用键盘输入他的名字 name。偶尔,在键入字符 c 时,按键可能会被长按,而字符可能被输入 1 次或多次。 你将会检查键盘输入的字符 typed。如果它对应的可能是你的朋友的名字&am…...
【Rust自学】15.2. Deref trait Pt.1:什么是Deref、解引用运算符*与实现Deref trait
喜欢的话别忘了点赞、收藏加关注哦,对接下来的教程有兴趣的可以关注专栏。谢谢喵!(・ω・) 15.2.1. 什么是Deref trait Deref的全写是Dereference,就是引用的英文reference加上"de"这个反义前缀,…...
图书管理系统 Axios 源码__新增图书
目录 功能介绍 核心代码解析 源码:新增图书功能 总结 本项目基于 HTML、Bootstrap、JavaScript 和 Axios 开发,实现了图书的增删改查功能。以下是新增图书的功能实现,适合前端开发学习和项目实践。 功能介绍 用户可以通过 模态框…...
吴恩达深度学习——超参数调试
内容来自https://www.bilibili.com/video/BV1FT4y1E74V,仅为本人学习所用。 文章目录 超参数调试调试选择范围 Batch归一化公式整合 Softmax 超参数调试 调试 目前学习的一些超参数有学习率 α \alpha α(最重要)、动量梯度下降法 β \bet…...
【赵渝强老师】K8s中Pod探针的ExecAction
在K8s集群中,当Pod处于运行状态时,kubelet通过使用探针(Probe)对容器的健康状态执行检查和诊断。K8s支持三种不同类型的探针,分别是:livenessProbe(存活探针)、readinessProbe&#…...
如何对系统调用进行扩展?
扩展系统调用是操作系统开发中的一个重要任务。系统调用是用户程序与操作系统内核之间的接口,允许用户程序执行内核级操作(如文件操作、进程管理、内存管理等)。扩展系统调用通常包括以下几个步骤: 一、定义新系统调用 扩展系统调用首先需要定义新的系统调用的功能。系统…...
ChatGPT与GPT的区别与联系
ChatGPT 和 GPT 都是基于 Transformer 架构的语言模型,但它们有不同的侧重点和应用。下面我们来探讨一下它们的区别与联系。 1. GPT(Generative Pre-trained Transformer) GPT 是一类由 OpenAI 开发的语言模型,基于 Transformer…...
