使用 CFFI 在 Python 中创建 CData 类型的缓冲区
Posted
技术标签:
【中文标题】使用 CFFI 在 Python 中创建 CData 类型的缓冲区【英文标题】:Create a CData-typed buffer in Python with CFFI 【发布时间】:2016-09-10 03:28:00 【问题描述】:我正在尝试在 Python 中创建一个特殊类型的缓冲区,以将其发送到用 CFFI 包装的 C 函数。
在 C 中,我有类似的东西:
typedef unsigned char UINT8;
typedef UINT8* PUINT8;
然后,在 Python 中,以上行在 ffi.cdef()
中,我的缓冲区实例化代码如下所示:
nb_buffer = 8
buffer_size = 42
buffers = ffi.new( "PUINT8[]", nb_buffer )
for i in range( nb_buffer ):
tmp_buffer = ffi.buffer( ffi.new( "UINT8[]", 1 ), buffer_size )
buffers[ i ] = ffi.cast( "PUINT8", ffi.from_buffer( tmp_buffer ) )
c.function( buffers )
C 函数接收一个 UINT8**。
并且...在 C 函数中以更远的分段错误结束。
所以我在使用ffi.cast
后print buffers[ i ]
:
<cdata 'unsigned char *' 0x2cbaca0>
<cdata 'unsigned char *' 0x2cbacd8>
<cdata 'unsigned char *' 0x2cbaca0>
<cdata 'unsigned char *' 0x2cbacd8>
<cdata 'unsigned char *' 0x2cbaca0>
<cdata 'unsigned char *' 0x2cbacd8>
<cdata 'unsigned char *' 0x2cbaca0>
<cdata 'unsigned char *' 0x2cbacd8>
我错过了什么?缓冲区是否在覆盖tmp_buffer
后立即被垃圾回收?
【问题讨论】:
不看细节,但ffi.buffer( ffi.new( "UINT8[]", 1 ), ... )
基本是错的。它的意思是“分配一个数组(一个 UINT8 的);然后为它取一个缓冲区;然后立即忘记新数组,以便立即释放它”。
另外,您分配一个 UINT8 的数组,然后将它们视为 42 字节缓冲区。最后 41 个字节无论如何都没有分配。
我认为ffi.buffer()
的第一个参数的重要性是 CData 的类型,而不是它的长度(因为它是第二个参数)并且它会以某种方式创建一个给定的 CData 类型给定大小的缓冲区。但我现在明白,第二个参数用于分割比需要更大的内存大小。谢谢阿明!我会尽快尝试你的答案。
ffi.buffer()
没有分配任何内存,它只是返回现有内存的视图。
【参考方案1】:
使用列表推导:
keepalive = [ ffi.new( "UINT8[]", buffer_size ) for i in range( nb_buffer ) ]
buffers = ffi.new( "PUINT8[]", keepalive )
c.functions( buffers )
# keepalive stays alive at least until here
【讨论】:
【参考方案2】:怎么样:
buffers = ffi.new( "PUINT8[]", nb_buffer )
keepalive = []
for i in range( nb_buffer ):
p = ffi.new("UINT8[]", buffer_size)
keepalive.append(p)
buffers[i] = p
c.function( buffers )
# keepalive stays alive at least until here
【讨论】:
以上是关于使用 CFFI 在 Python 中创建 CData 类型的缓冲区的主要内容,如果未能解决你的问题,请参考以下文章
在 Python CFFI 中声明包含 time_t 字段的结构
使用带有嵌入式 PyPy 的外部“Python”样式 cffi 回调