Python 指向Ctypes中c_int16数组缓冲区的指针
我正在用Python Ctypes为C dll编写一个包装器。在C库中,我有一个类似的函数Python 指向Ctypes中c_int16数组缓冲区的指针,python,c,pointers,dll,ctypes,Python,C,Pointers,Dll,Ctypes,我正在用Python Ctypes为C dll编写一个包装器。在C库中,我有一个类似的函数 int32 Transfer ( ..., PIN_PARAMS_TRANSFERDATA pInData, ... ) 其中,PIN_PARAMS_TRANSFERDATA是指向此结构的指针: typedef struct { ... void * pDataBuffer; //!< Pointer to application-allocated buff
int32 Transfer ( ..., PIN_PARAMS_TRANSFERDATA pInData, ... )
其中,PIN_PARAMS_TRANSFERDATA
是指向此结构的指针:
typedef struct
{
...
void * pDataBuffer; //!< Pointer to application-allocated buffer to hold requested data.
} IN_PARAMS_TRANSFERDATA, *PIN_PARAMS_TRANSFERDATA;
现在我遇到的问题是,在调用Transfer
函数之前,我必须定义一个数据缓冲区,我不管理这个函数。我尝试了以下方法(2000只是为了测试,应该是一个变量):
输出信息为:
<__main__.c_short_Array_2000 object at 0x00000000053D2EC8>
Traceback (most recent call last):
File ".../test.py", line 48, in <module>
in_data.pDataBuffer = byref(data_buffer)
TypeError: cannot be converted to pointer
编辑
根据J.F.Sebastian的建议,我稍微改变了缓冲区的创建:
data_buffer = (c_int16*2000)()
p_data_buffer = ctypes.cast(data_buffer, POINTER(c_int16*2000))
in_data.pDataBuffer = p_data_buffer
这给了我一个稍微不同的错误:
Traceback (most recent call last):
File ".../test.py", line 50, in <module>
in_data.pDataBuffer = p_data_buffer
TypeError: incompatible types, LP_c_short_Array_2000 instance instead of c_void_p instance
回溯(最近一次呼叫最后一次):
文件“../test.py”,第50行,在
in_data.pDataBuffer=p_data_buffer
TypeError:不兼容的类型,LP_c_short_Array_2000实例而不是c_void_p实例
ctypes.c\u void\u p
表示为一个整数。您可以将数组的地址传递给它:
>>> from ctypes import *
>>> class IN_PARAMS_TRANSFERDATA(Structure):
... _fields_ = [('pDataBuffer', c_void_p)]
...
>>> ArrayType = c_int16 * 2000
>>> in_data = IN_PARAMS_TRANSFERDATA()
>>> data_buffer = ArrayType(1,2,3) # set the first three values
>>> in_data.pDataBuffer = c_void_p(addressof(data_buffer))
>>> # or cast(data_buffer, c_void_p)
获取返回的值:
>>> cast(in_data.pDataBuffer, POINTER(ArrayType)).contents[:3]
[1, 2, 3]
以下是前三个值
要从指针获取numpy
数组,请参阅:
另一种可能是使用VirtualAlloc,就像在原始C代码中一样
p_data_buffer = ctypes.windll.kernel32.VirtualAlloc(c_int(0), c_int(sizeof(c_int16)*2000), c_int(0x00001000), c_int(0x04))
in_data.pDataBuffer = p_data_buffer
要想找回数据:
target = (c_int16*2000)()
ctypes.windll.kernel32.RtlMoveMemory(target, in_data.pDataBuffer, c_int(sizeof(c_int16)*2000))
data = numpy.frombuffer(target, dtype=c_int16)
你可以找到更多的细节。不过,我假设这段代码是针对Windows的。请尝试
ctypes.cast(data\u buffer,ctypes.POINTER(ArrayType))
而不是byref(data\u buffer)
,其中ArrayType=c\u int16*2000
请参见“谢谢您的提示”。事实上,现在到指针的转换工作了。但是,我仍然无法将此指针指定给\u data.pDataBuffer中的,因为类型与c\u void\u p
不匹配。我会更新这个问题。你试过cast(data\u buffer,c\u void\u p)
吗?我现在试过了,它运行了。但是我现在在访问缓冲区中的数据时遇到了问题。我假设我只需执行list(在_data.pDataBuffer中)
即可获得包含缓冲区中所有元素的列表。但是我得到了一个错误,'long'对象是不可编辑的。我试图回溯到指针(c_int16*2000)
,然后应用list()
,但这种方法永远运行,没有任何结果。这种方法非常有效。作为参考,我还将使用我发现的VirtualAlloc编写一个答案。1-您不需要经常编写c_int
:VirtualAlloc(NULL,sizeof(ArrayType),MEM_COMMIT,PAGE_READWRITE)
其中NULL=None
,MEM_COMMIT,PAGE_READWRITE=0x1000,0x4
应该可以工作。2-使用target=ArrayType()
并传递sizeof(ArrayType)
。避免在代码中使用神奇的常量,或给它们取有意义的名称。
>>> cast(in_data.pDataBuffer, POINTER(ArrayType)).contents[:3]
[1, 2, 3]
>>> import numpy
>>> pa = cast(in_data.pDataBuffer, POINTER(ArrayType))
>>> a = numpy.frombuffer(pa.contents, dtype=c_int16)
>>> a
array([1, 2, 3, ..., 0, 0, 0], dtype=int16)
p_data_buffer = ctypes.windll.kernel32.VirtualAlloc(c_int(0), c_int(sizeof(c_int16)*2000), c_int(0x00001000), c_int(0x04))
in_data.pDataBuffer = p_data_buffer
target = (c_int16*2000)()
ctypes.windll.kernel32.RtlMoveMemory(target, in_data.pDataBuffer, c_int(sizeof(c_int16)*2000))
data = numpy.frombuffer(target, dtype=c_int16)