Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/c/56.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 指向Ctypes中c_int16数组缓冲区的指针_Python_C_Pointers_Dll_Ctypes - Fatal编程技术网

Python 指向Ctypes中c_int16数组缓冲区的指针

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

我正在用Python Ctypes为C dll编写一个包装器。在C库中,我有一个类似的函数

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)