ctypes使用浅谈

news2024/11/28 12:33:53

什么是ctypes:

  ctypes 是 Python 的一个标准库,用于与 C 语言进行交互。它提供了一组工具和函数,可以方便地调用动态链接库(DLL)或共享对象(SO)中的 C 函数,并处理 C 数据类型的转换。

说的易懂点就是ctypes在c与python之间做类型转换的。既然是做类型转换的,那么对于c/c++中常用的类型,是如何用ctypes方式去做转换的,接下来一探究竟:

什么是动态链接库:

  动态链接库是一个已经编译好、程序在运行时就可直接使用的数据-函数库。与静态链接库不同,动态链接库在程序运行时被加载和链接,而不是在编译时动态链接库必须先载入,为此ctypes提供三个对象:cdll、windll(windows-only)、oledll(windows-only),并使得载入dll就如访问这些对象的属性一样。这三个区别是:

(1) cdll:cdll对象载入使用标准cdecl调用约定的函数库

(2) windll:windll对象载入使用stdcall调用约定的函数库

(3) oledll:oledll对象载入使用stdcall调用约定的函数库

使用步骤:

(1) 加载动态链接库:

  使用 ctypes 的 cdll 或 windll (Windows 平台)函数来加载动态链接库或共享对象。只需要提供库的路径或名称,ctypes 将自动根据操作系统的不同来选择正确的加载函数,

示例如下:


# 示例 1: 加载动态链接库
my_lib = ctypes.CDLL('/path/to/my_lib.so')
 
# 示例 2: 加载共享对象(在 Windows 上)
my_lib = ctypes.windll.LoadLibrary('my_lib.dll')

(2) 获取DLL/共享库中的函数

my_function = my_lib.my_function # my_function 是动态库中已导出的函数,不导出则不可调用,像访问一个类实例属性一样来载入my_function.argtypes = [ctypes.c_int, ctypes.c_float] my_function.restype = ctypes.c_double # 指定函数的返回类型和参数类型。

(3) 进行类型转换,从而可以传给调用的c函数:  

(1)C语言中基础的数据类型

这部分的使用比较简单,直接使用ctypes内置的方法创建对象即可,ctypes提供的方法和C语言对应的数据类型如下表:

ctypes 类型

C 类型

Python 类型

c_bool

_Bool

bool (1)

c_char

char

单字符字节串对象

c_wchar

wchar_t

单字符字符串

c_byte

char

int

c_ubyte

unsigned char

int

c_short

short

int

c_ushort

unsigned short

int

c_int

int

int

c_uint

unsigned int

int

c_long

long

int

c_ulong

unsigned long

int

c_longlong

__int64 或 long long

int

c_ulonglong

unsigned __int64 或 unsigned long long

int

c_size_t

size_t

int

c_ssize_t

ssize_t 或 Py_ssize_t

int

c_float

float

float

c_double

double

float

c_longdouble

long double

float

c_char_p

char* (以 NUL 结尾)

字节串对象或 None

c_wchar_p

wchar_t* (以 NUL 结尾)

字符串或 None

c_void_p

void*

int 或 None

使用的几个小示例:


import ctypes
 
# 加载动态链接库
my_lib = ctypes.CDLL('/path/to/my_lib.so')
 
# 定义函数原型
my_function = my_lib.my_function
my_function.argtypes = [ctypes.c_int]
 
# 转换整型数据类
my_int = 10
my_function(ctypes.c_int(my_int))
 
#转换浮点型数据类型:
my_float = 3.14
my_function(ctypes.c_float(my_float))
 
#转换字符串类型:
my_string = "Hello"
my_function(ctypes.c_char_p(my_string.encode('utf-8')))#转换数组类型:char_array = c_char * 3

(2)C语言中高级数据类型

对于 C 语言中的高级数据类型,如结构体、嵌套结构体、结构体数组、结构体指针等,ctypes 提供了一些工具和方法来进行转换。假设在 C 代码中有一个结构体类型 MyStruct,下面是几个示例:

import ctypes
 
# 定义 C 结构体类型
class MyStruct(ctypes.Structure):
    _fields_ = [("field1", ctypes.c_int),
                ("field2", ctypes.c_float)]
 
# 加载动态链接库
my_lib = ctypes.CDLL('/path/to/my_lib.so')
 
# 定义函数原型
my_function = my_lib.my_function
my_function.argtypes = [MyStruct]
 
# 创建结构体实例并传递给 C 函数
my_struct = MyStruct()
my_struct.field1 = 10
my_struct.field2 = 3.14
my_function(my_struct)
#转换嵌套结构体
class InnerStruct(ctypes.Structure):
    _fields_ = [("inner_field", ctypes.c_int)] # 定义 C 内部引用结构体class OuterStruct(ctypes.Structure):
    _fields_ = [("outer_field", ctypes.POINTER(InnerStruct))] # 创建结构体实例,并传递给 C 函数
inner = InnerStruct()
inner.inner_field = 10
 
outer = OuterStruct()
outer.outer_field = ctypes.pointer(inner)
 
my_function(ctypes.cast(ctypes.pointer(outer), ctypes.POINTER(OuterStruct)))array_size = 5
my_array = (MyStruct * array_size)()
for i in range(array_size):
    my_array[i].field1 = i
    my_array[i].field2 = float(i)
 
my_function(my_array, array_size)#转换结构体指针和结构体指针数组:#对于结构体指针和结构体指针数组,可以使用 ctypes.POINTER 类型和 ctypes.cast 函数进行转换。# 定义函数原型
my_function = my_lib.my_function
my_function.argtypes = [ctypes.POINTER(MyStruct)]
 
# 创建结构体实例,并传递给 C 函数
my_struct = MyStruct()
my_struct.field1 = 10
my_struct.field2 = 3.14
 
# 传递结构体指针给 C 函数
my_function(ctypes.pointer(my_struct))
 
# 创建结构体指针数组,并传递给 C 函数
array_size = 5
my_array = (ctypes.POINTER(MyStruct) * array_size)()
for i in range(array_size):
    my_array[i] = ctypes.pointer(MyStruct())
     
my_function(ctypes.cast(my_array, ctypes.POINTER(ctypes.POINTER(MyStruct)))) 

(3)C语言中回调函数的转换

假设在 C 代码中有一个函数 register_callback,它接受一个函数指针作为参数,并在适当的时候调用该函数。我们可以使用 ctypes 来定义回调函数,并将其传递给 register_callback

首先,我们需要定义回调函数的类型,然后将其转换为函数指针类型。在调用 register_callback 时,我们将转换后的函数指针作为参数传递。

import ctypes
 
# 定义回调函数类型
CallbackFunc = ctypes.CFUNCTYPE(None, ctypes.c_int)
 
# 定义回调函数
def my_callback(value):
    print("Callback called with value:", value)
 
# 加载动态链接库
my_lib = ctypes.CDLL('/path/to/my_lib.so')
 
# 定义函数原型
register_callback = my_lib.register_callback
register_callback.argtypes = [CallbackFunc]
 
# 将 Python 回调函数转换为函数指针
callback_func = CallbackFunc(my_callback)
 
# 注册回调函数
register_callback(callback_func)

首先使用 ctypes.CFUNCTYPE 定义了回调函数类型 CallbackFunc。它的第一个参数是回调函数的返回类型,这里是 None,表示没有返回值;第二个参数是回调函数的参数类型,这里是 ctypes.c_int

然后,我们定义了 Python 中的回调函数 my_callback,它接受一个整数参数,并在函数内部打印该参数的值。

接下来,我们使用 CallbackFunc 将 Python 回调函数转换为函数指针类型 callback_func

最后,我们加载动态链接库,并调用 register_callback 函数,将转换后的函数指针作为参数传递给 C 函数。


 资料获取方法

【留言777】

各位想获取源码等教程资料的朋友请点赞 + 评论 + 收藏,三连!

三连之后我会在评论区挨个私信发给你们~

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/858230.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

探索自动化网页交互的魔力:学习 Selenium 之旅【超详细】

"在当今数字化的世界中,网页自动化已经成为了不可或缺的技能。想象一下,您可以通过编写代码,让浏览器自动执行各种操作,从点击按钮到填写表单,从网页抓取数据到进行自动化测试。学习 Selenium,这一功能…

用普通用户sudo执行ansibe命令

1、编辑/etc/ansible/ansible.cfg 2、hosts文件 3、执行命令 必须加-b选项

无涯教程-Perl - goto函数

描述 该函数具有三种形式,第一种形式使当前执行点跳到称为LABEL的点。这种形式的goto不能用于跳入循环或外部函数。您只能跳至同一范围内的一点。 第二种形式期望EXPR判断为可识别的LABEL。通常,您应该能够使用普通的条件语句或函数来控制程序的执行,因此不建议使用该程序。 …

配置service启动nginx

一.以源码形式安装的nginx,没有nginx.service 二.切换到service配置目录 三.编辑nginx.service文件 四.启动测试 1.我的开始报了这个问题,说没有这个/var/cache/nginx/client_temp目录,直接创建一个就好了 2.开启/关闭 一.以源码形式安装…

【Flutter】【基础】CustomPaint 绘画功能(一)

功能:CustomPaint 相当于在一个画布上面画画,可以自己绘制不同的颜色形状等 在各种widget 或者是插件不能满足到需求的时候,可以自己定义一些形状 使用实例和代码: CustomPaint: 能使你绘制的东西显示在你的ui 上面&a…

Mapbox加载天地图CGCS2000矢量瓦片地图

1.背景 最近在做天地图的项目,要基于MapBox添加CGCS2000矢量切片数据,但是 Mapbox 只支持web 墨卡托(3857)坐标系的数据。Github有专业用户修改了mapbox-gl的相关代码,支持CGCS2000的切片数据加载,并且修改…

idea添加作者信息

idea添加作者信息 在idea中,经常会有这些波浪纹提示,放在上面之后会提示添加作者信息,点击添加作者信息后,但是不是自己想要的 这里提取的话好像没什么办法修改,可能修改电脑的名称。这样提取出来才是自己需要的 自定义作者信息…

基于Java+SpringBoot+Vue的网上书城管理系统设计与实现(源码+LW+部署文档等)

博主介绍: 大家好,我是一名在Java圈混迹十余年的程序员,精通Java编程语言,同时也熟练掌握微信小程序、Python和Android等技术,能够为大家提供全方位的技术支持和交流。 我擅长在JavaWeb、SSH、SSM、SpringBoot等框架…

CSS:background 复合属性详解(用法 + 例子 + 效果)

目录 background 复合属性background-color 背景颜色(纯)background-image 背景图片 或者 渐变颜色background-repeat 背景是否重复background-size 设置图片大小background-position 设置背景图片显示位置background-attachment 设置背景图片是否随页面…

软件包管理

一、rpm管理软件包 1、获得rpm的软件包 1)去官网安装不推荐 找自己光盘有没有这个包 装好需要的包之后装qq 2)去镜像站点,推荐 二、yum/dnf管理软件包 解决软件的依赖关系,可以自动的去服务器下载软件包 1、使用yum软件包 使用…

clion run qt 问题汇总

一、Error copying file “D:/soft/QT/5.15.2/mingw81_64/bin/Qt5Cored.dll” to “D:/work/Ccode/qtproject/cmake-build-debug-qtmingw”.报错 查看路径下确实没有Qt5Cored.dll,只有Qt5Core.dll 注释掉cmakelist中的这三行 重新执行后成功 二、使用CLion编辑u…

【Autolayout案例02-距离四周边距 Objective-C语言】

一、好,来看第二个案例 1.第二个案例,是什么意思呢,第二个案例,要求屏幕中间,有一个UIView UIView,是个红色的UIView UIView的大小,我不限定 但是无论你是什么屏幕下 这个UIView距离上边,始终是50 距离右边,始终是50, 距离下边,始终是50, 距离左边,始终是5…

【运维工程师学习八】代理及安装配置Nginx反向代理

【运维工程师学习八】代理 正向代理一、使用正向代理的主要作用有:二、反向代理三、使用反向代理的主要作用有:四、透明代理五、各种代理的主要区别六、Nginx的安装七、了解nginx的文件位置八、了解nginx程序的命令行参数九、开启nginx反向代理十、解读n…

变频谐振耐压试验装置产品概述及特点

一、产品概述 KDXZ-II 75kVA/75kV串联谐振耐压试验装置主要针10kV电缆及以下电力主变压器、母线开关等所有电气主设备的交流耐压试验设计制造。电抗器采用多只分开设计,既可满足高电压、小电流的设备试验条件要求,又能满足象10kV电缆这样的低电压的交流…

机器学习——SVM核函数

核函数这块,原理理解起来,相对比较简单 但还是会有一些不太理解的地方 对于非线性可分的数据而言,在当前维度,直接使用SVM有分不出的情况 那么就可以从当前维度,直接升到更高维度,进行计算。 例如原本数…

pytest fixture 高级使用

一、fixture中调用fixture 举例: 输出: 说明:登录fixture 作为参数传递到登出方法中,登录方法的返回值就可以被登出方法使用 二、在fixture中多参数的传递(通过被调用函数传参) 举例: 输出&a…

我的5年创作纪念日

CSDN的5周年来信 机缘 初心是什么?初心就是自己最初成为创作者的动力和目标。作为一个程序员,我对编程充满了热情和执着。我在实战项目中积累了丰富的经验,并希望能将这些经验分享给更多的人。通过写博客,我可以记录下日常学习的…

来的真快:微信小程序必须要备案,否则下架

我是卢松松,点点上面的头像,欢迎关注我哦! 随着上面的一声令下(工信部要求所有APP、小程序进行备案),各大互联网大厂都开始实施具体政策了。来的可真快啊! 首先来的就是微信公众号,它是跟进政策是最快的了。微信公众…

搭建一个自己的文档网站

目录 简介 快速上手 配置 首页 组件Demo案例 简介 有时候我们可能很好奇,像elementUi或者vue3他们的文档网站是怎么写的,其实写vue文档网站的技术,有两个:一个是vuePress,一个是vitePress。从名字上可以看出来&#…

百度chatgpt内测版

搜索AI伙伴 申请到了百度的chatgpt: 完整的窗口布局: 三个哲学问题: 灵感中心: 请做一副画,一个渔夫,冬天,下着大雪,在船上为了一家的生计在钓鱼,远处的山上也都是白雪&a…