Python 使用ctypes将指针类型的参数传递给指向C函数的指针

Python 使用ctypes将指针类型的参数传递给指向C函数的指针,python,ctypes,Python,Ctypes,myC函数的定义为- foo(int64_t* total_length, const int8_t* fromtags, int64_t fromtagsoffset, const int32_t* fromindex, int64_t fromindexoffset, int64_t length, int64_t** offsetsraws, int64_t* offsetsoffsets) 我可以通过Pythonas中的ctypes加载它- import ctypes lib = ct

my
C
函数的定义为-

foo(int64_t* total_length,
const int8_t* fromtags,
int64_t fromtagsoffset,
const int32_t* fromindex,
int64_t fromindexoffset,
int64_t length,
int64_t** offsetsraws,
int64_t* offsetsoffsets)
我可以通过
Python
as中的
ctypes
加载它-

import ctypes
lib = ctypes.CDLL("....")
name = "foo"
funcC = getattr(lib, name)
我可以设置它需要的参数类型-

funcC.argtypes = (ctypes.POINTER(ctypes.c_int64), ctypes.POINTER(ctypes.c_int8), ctypes.c_int64, ctypes.POINTER(ctypes.c_int32), ctypes.c_int64, ctypes.c_int64, ctypes.POINTER(ctypes.POINTER(ctypes.c_int64)), ctypes.POINTER(ctypes.c_int64))
我指定要传递给func的值,如-

temparr = [0]*30
total_length = ((ctypes.c_int64)*30)(*temparr)
temparr = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
fromtags = ((ctypes.c_int8)*len(temparr))(*temparr)
fromtagsoffset = 1
temparr = [1, 2, 6, 6, 3, 7, 3, 8, 3, 8, 8]
fromindex = ((ctypes.c_int32)*len(temparr))(*temparr)
fromindexoffset = 0
length = 3
temparr = [0, 0, 1, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1]
offsetsoffsets = ((ctypes.c_int64)*len(temparr))(*temparr)
对于类型为pointer to pointer的参数,我指定如下值-

temparr = [1, 2, 1, 2, 1, 2, 3, 4, 1, 2, 3, 4, 1, 2, 3, 4]
offsetsraws = ctypes.pointer((ctypes.c_int64 * len(temparr))(*temparr))
然后我用参数创建一个
列表
-

testsc = [total_length, fromtags, fromtagsoffset, fromindex, fromindexoffset, length, offsetsraws, offsetsoffsets]
最后,我将参数传递给
func
-

funcC(*testsc)
但我犯了个错误-

Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ctypes.ArgumentError: argument 7: <class 'TypeError'>: expected LP_LP_c_long instance instead of LP_c_long_Array_16
回溯(最近一次呼叫最后一次):
文件“”,第1行,在
ctypes.ArgumentError:Argument7::应为LP_LP_c_long实例,而不是LP_c_long_数组_16
我应该如何修复此错误

是不是因为我在将
offsetsraws
argtype指定为
ctypes.POINTER(ctypes.POINTER(ctypes.c_int64))
时出错了

我发现了一个类似的问题——但区别在于,在这个问题中,传递的指针指针在输入过程中没有赋值,更重要的是,它没有表示为2D数组。

清单

如果您有一个指向一维数组的指针(大约90%+的情况),则可以执行从int64[]到int64*的简单转换
但是,如果您有一个二维数组,事情会变得更复杂,因为您必须分别处理每个单独的一维数组(行)(例如(以及它引用的其他URL))

这是前一个例子

>将ctypes作为ct导入
>>>
>>>
>>>gtc=ct.windell.kernel32.GetTickCount#此函数不接受参数。我使用它只是为了演示的目的!!!基本上,这是未定义的行为。
>>>gtc.argtypes=[ct.POINTER(ct.POINTER(ct.c_int64))]
>>>
>>>arr=[1,2,1,2,1,2,3,4,1,2,3,4,1,2,3,4]
>>>
>>>arr_ct=ct.pointer((ct.c_int64*len(arr))(*arr))#原始变量
>>>
>>>gtc(arr#u ct)#将引发异常
回溯(最近一次呼叫最后一次):
文件“”,第1行,在
ctypes.ArgumentError:参数1::应为LP_LP_c_longlong实例,而不是LP_c_longlong_数组16
>>>
>>>arr_ct=ct.pointer(ct.cast((ct.c_int64*len(arr))(*arr),ct.pointer(ct.c_int64))#将(内部)数组强制转换为指针
>>>
>>>gtc(arr_ct)
250935781
>>> import ctypes as ct
>>>
>>>
>>> gtc = ct.windll.kernel32.GetTickCount  # This function does NOT take arguments. I used it for DEMO PURPOSES ONLY !!! Basically, it's Undefined Behavior.
>>> gtc.argtypes = [ct.POINTER(ct.POINTER(ct.c_int64))]
>>>
>>> arr = [1, 2, 1, 2, 1, 2, 3, 4, 1, 2, 3, 4, 1, 2, 3, 4]
>>>
>>> arr_ct = ct.pointer((ct.c_int64 * len(arr))(*arr))  # Original variant
>>>
>>> gtc(arr_ct)  # Will throw exception
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ctypes.ArgumentError: argument 1: <class 'TypeError'>: expected LP_LP_c_longlong instance instead of LP_c_longlong_Array_16
>>>
>>> arr_ct = ct.pointer(ct.cast((ct.c_int64 * len(arr))(*arr), ct.POINTER(ct.c_int64)))  # cast the (inner) array to pointer
>>>
>>> gtc(arr_ct)
250935781