[Python]pytorch与C交互

文章目录

    • C++库
    • ctypes
      • 基础数据类型
      • 参数与返回值类型
      • 数组
      • 指针
      • 结构体类型
      • 回调函数
      • 工具函数
    • 示例

ctypes是Python的外部函数,提供了与C兼容的类型,并允许调用DLL库中的函数。

C++库

要使函数能被Python调用,需要编译为动态库:

# -fPIC使得位置独立
# -shared代表这是动态库
g++ -fPIC -shared -o libTest.so test.cpp

为保证函数接口能被外部识别,需要导出为纯C的:

#ifdef __cplusplus
extern "C"
{
#endifvoid * callForTest(char *params);#ifdef __cplusplus
};
#endif

ctypes

在python中要使用DLL库,需要先通过cdll来加载(cdll载入按标准的 cdecl调用协议导出的函数):

from ctypes import cdlltarget = cdll.LoadLibrary("libTest.so")

通过in_dll()可获取库中导出的变量:

# 获取 Python 库本身的 Py_OptimizeFlag
opt_flag = c_int.in_dll(pythonapi, "Py_OptimizeFlag")

基础数据类型

ctypes 定义了一些和C兼容的基本数据类型,所有基础类型都继承自ctypes._SimpleCData

  • value属性:包含实例的实际值。实例提取 value 属性时,通常每次会返回一个新的对象。
ctypes 类型C 类型Python 类型
c_bool_Boolbool (1)
c_charchar1-character bytes
c_wcharwchar_t1-character str
c_bytecharint
c_ubyteunsigned charint
c_shortshortint
c_ushortunsigned shortint
c_intintint
c_uintunsigned intint
c_longlongint
c_ulongunsigned longint
c_longlong__int64 or long longint
c_ulonglongunsigned __int64 or unsigned long longint
c_size_tsize_tint
c_ssize_tssize_t or Py_ssize_tint
c_floatfloatfloat
c_doubledoublefloat
c_longdoublelong doublefloat
c_char_pchar* (NUL terminated)bytes or None
c_wchar_pwchar_t* (NUL terminated)str or None
c_void_pvoid*int or None

除了整数、字符串以及字节串之外,所有的Python类型都必须使用它们对应的ctypes类型包装,才能够被正确地转换为所需的C语言类型。通过ctypes创建的类型是可变的(通过修改.value):

i = c_int()
# i.value == 0
i.value = 99
# i.value == 99c_wchar_p("Hello, World")
# c.value == "Hello, World"

当给指针类型的对象c_char_p, c_wchar_p 和 c_void_p等赋值时,将改变它们所指向的内存地址,而不是它们所指向的内存区域的内容。若底层函数可能会改变指针地址,则需要通过create_string_buffer创建:

p = create_string_buffer(3) # create a 3 byte buffer, initialized to NUL bytesp = create_string_buffer(b"Hello") # create a buffer containing a NUL terminated stringp = create_string_buffer(b"Hello", 10) # create a 10 byte buffer
p.value = b"Hi"
print(sizeof(p), repr(p.raw))
# 10 b'Hi\x00lo\x00\x00\x00\x00\x00'

参数与返回值类型

以libc库为例:

cdll.LoadLibrary("libc.so.6")printf = libc.printf
# 通过设置argtypes属性来指定函数的必选参数类型
# 指定数据类型可以防止不合理的参数传递,并且会自动尝试将参数转换为需要的类型(否则必须手动转换)
printf.argtypes = [c_char_p, c_char_p, c_int, c_double]
printf(b"String '%s', Int %d, Double %f\n", b"Hi", 10, 2.2)strchr = libc.strchr
# 默认返回int,其他类型需通过restype属性来设定
strchr.restype = c_char_p
strchr.argtypes = [c_char_p, c_char]
strchr(b"abcdef", b"d")# 构造缓冲区,获取输出
i = c_int()
f = c_float()
s = create_string_buffer(b'\x00' * 32) # 创建长度32,全部为NULL的缓冲区
libc.sscanf(b"1 3.14 Hello", b"%d %f %s", byref(i), byref(f), s)
print(i.value, f.value, repr(s.value))
# 1 3.140000104904175 b'Hello'

数组

数组是一个序列,包含指定个数元素,且必须类型相同。创建数组类型的推荐方式是使用一个类型乘以一个正数:

  • _length_属性:指明数组中元素数量的正整数。
  • _type_属性:指明每个元素的类型。
class POINT(Structure):_fields_ = ("x", c_int), ("y", c_int)pointsArray = POINT * 5
print(sizeof(pointsArray))
# 40pa = pointArray(POINT(1,2), POINT(3,4)) # 后面三个全为0
print(sizeof(pa), len(pa))
# 40 5
for i in pa: print(i.x, i.y, end=";")
# 1 2;3 4;0 0;0 0;0 0;

指针

可以将ctypes类型数据传入pointer()函数创建指针:

  • contents属性:返回指针指向的真实对象( 每次访问这个属性时都会构造返回一个新的相同对象
  • _type_属性:指明所指向的类型。
  • 指针对象也可以通过整数下标进行访问;
  • 通过整数下标赋值可以改变指针所指向的真实内容;
  • 无参调用指针类型可以创建一个NULL指针;
i = c_int(12)
pi = pointer(i)
ic = pi.contentsprint(ic, ic is i)
# c_int(12) False# 通过下标访问与修改内容
pi[0]=34
print(pi[0], pi.contents)
# 34 c_int(34)# 修改指针指向
ii = c_int(45)
pi.contents = ii
print(pi[0])
# 56

结构体类型

结构体必须通过子类化ctypes.Structure来创建,并且至少要定义一个 _fields_类变量,并允许通过直接属性访问来读取和写入字段。

  • _fields_属性:定义结构体字段的序列。 其中的条目必须为2元组或3元组。
    • 第一项是字段名称;
    • 第二项指明字段类型,可以是任何 ctypes 数据类型;
    • 对于整数类型字段(如c_int),可以给定第三个可选项;为定义字段比特位宽度的小正整数。
  • _pack_属性:一个可选的小整数,它允许覆盖实体中结构体字段的对齐方式。

对于不完整类型:即在结构体中包含指向自身的指针:

struct cell; /* forward declaration */struct cell {char *name;struct cell *next;
};

在python中不能在类中使用自身,需要先定义结构,然后在设定_fields_属性:

class cell(Structure):passcell._fields_ = [("name", c_char_p),("next", pointer(cell))]

回调函数

必须先为回调函数创建一个类(明确调用约定,返回值类型以及参数信息);CFUNCTYPE()工厂函数使用 cdecl 调用约定创建回调函数类型。

qsort = libc.qsort
qsort.restype=None# 第一个参数为返回值类型,后续一次为对应函数参数
CMPFun = CFUNCTYPE(c_int, POINTER(c_int), POINTER(c_int))
def py_cmp_func(a,b):print('py_cmp_func', a[0], b[0])return 0cmp_fun = CMPFun(py_cmp_func)IntArray5 = c_int * 5
ia = IntArray5(1, 9, 7, 5, 8)
qsort(ia, len(ia), sizeof(c_int), py_cmp_func)

注意:回调函数是在Python之外的另外一个线程使用(外部代码调用这个回调函数), ctypes 会在每一次调用时创建一个虚拟 Python 线程。这个行为在大多数情况下是合理的,但也意味着如果有数据使用 threading.local 方式存储,将无法访问,就算它们是在同一个C线程中调用的。

工具函数

一些常用工具函数:

  • ctypes.addressof(obj):以整数形式返回内存缓冲区地址;obj 必须为一个 ctypes 类型的实例。
  • ctypes.alignment(obj_or_type):返回一个 ctypes 类型的对齐要求;obj_or_type 必须为一个 ctypes 类型或实例。
  • ctypes.byref(obj[, offset]):返回指向obj的引用,该对象必须为一个 ctypes 类型的实例。 offset 默认值为零,且必须为一个将被添加到内部指针值的整数。
  • ctypes.cast(obj, type):类似于 C 的强制转换运算符。 它返回一个 type 的新实例,该实例指向与 obj 相同的内存块。 type 必须为指针类型,而 obj 必须为可以被作为指针来解读的对象。
  • ctypes.create_string_buffer(init_or_size, size=None):创建一个可变的字符缓冲区。 返回的对象是一个 c_char 的 ctypes 数组。
    • init_or_size 必须是一个指明数组大小的整数,或者是一个将被用来初始化数组条目的字节串对象。
    • 如果将一个字节串对象指定为第一个参数,则将使缓冲区大小比其长度多一项以便数组的最后一项为一个 NUL 终结符。 可以传入一个整数作为第二个参数以允许在不使用字节串长度的情况下指定数组大小。
  • ctypes.create_unicode_buffer(init_or_size, size=None):创建一个可变的 unicode 字符缓冲区。
  • ctypes.get_errno():返回调用线程中系统 errno 变量的 ctypes 私有副本的当前值。
  • ctypes.memmove(dst, src, count):与标准 C memmove 库函数相同:将 count 个字节从 src 拷贝到 dst。 dst 和 src 必须为整数或可被转换为指针的 ctypes 实例。
  • ctypes.memset(dst, c, count):与标准 C memset 库函数相同:将位于地址 dst 的内存块用 count 个字节的 c 值填充。 dst 必须为指定地址的整数或 ctypes 实例。
  • ctypes.POINTER(type):创建并返回一个新的 ctypes 指针类型。 指针类型会被缓存并在内部重用,因此重复调用此函数耗费不大。 type 必须为 ctypes 类型。
  • ctypes.pointer(obj):创建一个新的指向 obj 的指针实例。 返回的对象类型为 POINTER(type(obj))。
    • 如果你只是想向外部函数调用传递一个对象指针,你应当使用更为快速的 byref(obj)。
  • ctypes.sizeof(obj_or_type):返回 ctypes 类型或实例的内存缓冲区以字节表示的大小。
  • ctypes.string_at(address, size=- 1):返回从内存地址 address 开始的以字节串表示的 C 字符串。 如果指定了 size,则将其用作长度,否则将假定字符串以零值结尾。
  • ctypes.wstring_at(address, size=- 1):返回从内存地址 address 开始的以字符串表示的宽字节字符串。

示例

以C++回调一个python函数为例:

C++中的回调定义:

#ifdef __cplusplus
extern "C"
{
#endiftypedef void (*PrintOutput)(const char* outputs);void set_callback(PrintOutput func);#ifdef __cplusplus
};
#endif

python中使用回调:

from ctypes import cdll, c_char_p, CFUNCTYPE, POINTERtarget = cdll.LoadLibrary("/workspace/libTest.so")PrintCallback = CFUNCTYPE(None, c_char_p)
def print_callback(outputs):print("outputs:", outputs)py_callback = PrintCallback(print_callback)target.set_callback.restype = None
target.set_callback(py_callback)    

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

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

相关文章

unity 之 GetComponent 获取游戏对象上组件实例方法

GetComponent 简单介绍 GetComponent 是Unity引擎中用于获取游戏对象上组件实例的方法。它允许您从游戏对象中获取特定类型的组件&#xff0c;以便在脚本中进行操作和交互。 GetComponent< ComponentType >(): 这是一个泛型方法&#xff0c;用于从当前游戏对象上获取指定…

HTML详解连载(8)

HTML详解连载&#xff08;8&#xff09; 专栏链接 [link](http://t.csdn.cn/xF0H3)下面进行专栏介绍 开始喽浮动-产品区域布局场景 解决方法清除浮动方法一&#xff1a;额外标签发方法二&#xff1a;单伪元素法方法三&#xff1a;双伪元素法方法四&#xff1a;overflow浮动-总结…

小程序商品如何指定打印机

有些商家&#xff0c;可能有多个仓库。不同的仓库&#xff0c;存放不同的商品。当客户下单时&#xff0c;小程序如何自动按照仓库拆分订单&#xff0c;如何让打印机自动打印对应仓库的订单呢&#xff1f;下面就来介绍一下吧。 1. 设置订单分发模式。进入管理员后台&#xff0c…

不花一分钱,利用免费电脑软件将视频MV变成歌曲音频MP3

教程 1.点击下载电脑软件下载地址&#xff0c;点击下载&#xff0c;安装。&#xff08;没有利益关系&#xff0c;没有打广告&#xff0c;只是单纯教学&#xff09; 2.安装完成后&#xff0c;点击格式工厂 3.然后如图所示依次&#xff0c;点击【音频】->【-MP3】 3.然后点击…

【ts】ts项目引入文件报红,进行全局类型声明的方法

vue3项目中使用ts&#xff0c;如果要引入的文件没有相应的类型声明文件&#xff0c;那么你需要为每个文件创建对应的类型声明文件 例如&#xff1a;我要引入index.vue文件。 那么就需要在src目录下创建index.vue.d.ts 的文件&#xff0c;要确保文件名与需要创建类型声明的模块…

[机缘参悟-100] :今早的感悟:儒释道代表了不同的人生观、思维模式决定了人的行为模式、创业到处是陷阱、梦想与欺骗其实很容易辨认

目录 一、关于儒释道 二、关于成长性思维与固定性思维 三、关于创业 四、关于梦想与忽悠 一、关于儒释道 儒&#xff1a;逆势而为&#xff0c;修身齐家治国平天下 佛&#xff1a;万法皆空&#xff0c;众生皆苦&#xff0c;普度众生。 道&#xff1a;顺势无为&#xff0c;天…

MySQL 自定义 split 存储过程

MySQL 没有提供 split 函数&#xff0c;但可以自己建立一个存储过程&#xff0c;将具有固定分隔符的字符串转成多行。之所以不能使用自定义函数实现此功能&#xff0c;是因为 MySQL 的自定义函数自能返回标量值&#xff0c;不能返回多行结果集。 MySQL 8&#xff1a; drop pr…

设计模式详解-装饰器模式

类型&#xff1a;结构型模式 实现原理&#xff1a;装饰器模式通过将对象包装在装饰器类中&#xff0c;并在保持类方法签名完整性的前提下&#xff0c;提供额外功能 作用&#xff1a;动态地给一个对象添加一些额外的职责。增加功能方面&#xff0c;装饰器模式比生成子类更灵活…

低代码系列——初步认识低代码

低代码系列目录 一、初步认识低代码 二、低代码是什么 三、低代码平台的概念和分类 01.无代码开发平台 02.低代码应用平台(LCAP) 03.多重体验开发平台(MXDP) 04.智能业务流程管理套件(iBPMS) 四、低代码的能力指标 五、低代码平台jnpf 表单 报表 流程 权限 一、初步认识低代码 …

【剖析STL】vector

vector的介绍及使用 1.1 vector的介绍 cplusplus.com/reference/vector/vector/ vector是表示可变大小数组的序列容器。就像数组一样&#xff0c;vector也采用的连续存储空间来存储元素。也就是意味着可以采用下标对vector的元素 进行访问&#xff0c;和数组一样高效。但是…

STM32开关输入控制220V灯泡亮灭源代码(附带PROTEUSd电路图)

//main.c文件 /* USER CODE BEGIN Header */ /********************************************************************************* file : main.c* brief : Main program body************************************************************************…

md文本学习

这里写自定义目录标题 欢迎使用Markdown编辑器新的改变功能快捷键合理的创建标题&#xff0c;有助于目录的生成如何改变文本的样式插入链接与图片如何插入一段漂亮的代码片生成一个适合你的列表创建一个表格设定内容居中、居左、居右SmartyPants 创建一个自定义列表如何创建一个…

将Swift Package构建为通用二进制文件 Universal Binary

将Swift软件包构建为通用二进制文件 因此&#xff0c;在苹果在WWDC 2020期间宣布他们将把Mac从英特尔处理器过渡到苹果硅之后&#xff0c;现在是时候让每个人都准备好他们的软件了。 对大多数人来说&#xff0c;这次过渡可能更容易一些&#xff0c;特别是那些已经在iOS上支持a…

中间件的介绍

1.1 什么是中间件 中间件是介于应用系统和系统软件之间的一类软件&#xff0c;他使用系统软件所提供的基础服务&#xff0c;衔接网络上应用系统的各个部分或不同的应用&#xff0c;能够达到资源共享、功能共享的目的。 例如MySQL就可以看作是具备中间件特性的一种技术&#x…

【Ubuntu】简洁高效企业级日志平台后起之秀Graylog

简介 Graylog 是一个用于集中式日志管理的开源平台。在现代数据驱动的环境中&#xff0c;我们需要处理来自各种设备、应用程序和操作系统的大量数据。Graylog提供了一种方法来聚合、组织和理解所有这些数据。它的核心功能包括流式标记、实时搜索、仪表板可视化、告警触发、内容…

vue+electron中实现文件下载打开wps预览

下载事件 win.webContents.downloadURL(url) 触发session的will-download事件 win.webContents.session.on(will-download, (event, downloadItem, webContents) > {// 设置文件保存路径// 如果用户没有设置保存路径&#xff0c;Electron将使用默认方式来确定保存路径&am…

IDEA开发项目时一直出现http404错误的解决方法

系列文章目录 安装cv2库时出现错误的一般解决方法_cv2库安装失败 SQL&#xff1e; conn sys/root as sysdbaERROR:ORA-12560: TNS: 协议适配器错误的解决方案 虚拟机启动时出现“已启用侧通道缓解”的解决方法 Hypervisor launch failed&#xff1b; Processor does not pr…

Component name “Home“ should always be multi-word

错误 解决方案 在根目录找到eslintrc.js文件&#xff0c;配置关闭名称的校验&#xff0c;在该文件中&#xff0c;找到rules进行配置&#xff0c;如下代码&#xff1a; rules: {vue/multi-word-component-names: off, // 关闭名称校验}

VScode替换cmd powershell为git bash 终端,并设置为默认

效果图 步骤 1. 解决VScode缺少git bash的问题_failed to start bash - is git-bash.exe on the syst_Rudon滨海渔村的博客-CSDN博客效果解决步骤找到git安装目录下的/bin/bash.exe&#xff0c;复制其绝对路径&#xff0c;例如D:\Program Files\Git\bin\bash.exe把路径的右斜…

.netcore grpc身份验证和授权

一、鉴权和授权&#xff08;grpc专栏结束后会开启鉴权授权专栏欢迎大家关注&#xff09; 权限认证这里使用IdentityServer4配合JWT进行认证通过AddAuthentication和AddAuthorization方法进行鉴权授权注入&#xff1b;通过UseAuthentication和UseAuthorization启用鉴权授权增加…