通过 Python 内的 c 函数传递和 return 双精度数组
pass and return an array of doubles through c function inside Python
我在 Python 代码中成功调用了一个 dll 库。所有按值函数都运行顺利。问题是我的 c 函数需要一个指向 return 结果的双精度数组指针。我不知道如何定义这个数组。
from ctypes import *
testlib = cdll.LoadLibrary(".\testdll.dll")
def wrap_func(lib, funcname, restype, argtypes):
func = lib.__getattr__(funcname)
func.restype = restype
func.argtypes = argtypes
return func
test1 = wrap_func(testlib, 'testfun1', c_double, [c_double, POINTER(c_double), POINTER(c_char)])
test2 = wrap_func(testlib, 'testfun2', c_double, [c_double])
a = 2.5
b = Pointer(c_double)
tstr = Pointer(c_char)
d = test1(a, b, tstr)
print(b.values)
test1 有问题。 test2 成功运行。
原函数test1 n C为:
double testfun1(double x, double* y, char* str)
我希望函数的输出通过数组b恢复。
错误是:
ctypes.ArgumentError: argument 2: <class 'TypeError'>: expected LP_c_double instance instead of _ctypes.PyCPointerType
有人能帮帮我吗?
在 ctypes 中,POINTER(c_double)
是 class 表示指向 c_double
的指针。您要传递的不是 class 本身,而是 class 的一个实例。这就是您收到错误消息的原因,即 "expected an instance of 'pointer to double' instead of the type 'pointer to double'".
由于 C 函数的这些参数没有关联的大小,我假设它们是 in/out 参数,在这种情况下,您需要让它们指向真实的对象。这应该有效:
b = c_double()
c = c_char()
d = test1(a, byref(b), byref(c))
如果它们是数组,您可以在 Python 中创建数组,然后使用您找到的 POINTER
classes 创建实例:
DoublePointer = POINTER(c_double)
CharPointer = POINTER(c_char)
b = DoublePointer.from_buffer(some_array)
d = test1(a, b, tstr)
如果将C函数的参数声明为c_char_p
,则可以直接在其中使用Python字符串,而无需将它们显式转换为指针。
听起来 b
是一个数组,但 testfun1
没有得到数组大小的指示,问题中也没有提到它。下面是 testfun1
的一个示例实现,假设数组是三个元素:
test.c
#ifdef _WIN32
# define API __declspec(dllexport)
#else
# define API
#endif
#include <stdio.h>
API double testfun1(double x, double* y, char* str)
{
printf("%lf %p %s\n",x,y,str);
y[0] = x;
y[1] = x * 2;
y[2] = x * 3;
return x * 4;
}
这是调用它的 Python 代码:
test.py
from ctypes import *
dll = CDLL('test')
test1 = dll.testfun1
test1.argtypes = c_double,POINTER(c_double),c_char_p
test1.restype = c_double
a = 2.5
b = (c_double * 3)() # create an array of three doubles
s = b'test123'
d = test1(a,b,s)
print(d,list(b))
输出
2.500000 000001CA3E31B330 test123
10.0 [2.5, 5.0, 7.5]
我在 Python 代码中成功调用了一个 dll 库。所有按值函数都运行顺利。问题是我的 c 函数需要一个指向 return 结果的双精度数组指针。我不知道如何定义这个数组。
from ctypes import *
testlib = cdll.LoadLibrary(".\testdll.dll")
def wrap_func(lib, funcname, restype, argtypes):
func = lib.__getattr__(funcname)
func.restype = restype
func.argtypes = argtypes
return func
test1 = wrap_func(testlib, 'testfun1', c_double, [c_double, POINTER(c_double), POINTER(c_char)])
test2 = wrap_func(testlib, 'testfun2', c_double, [c_double])
a = 2.5
b = Pointer(c_double)
tstr = Pointer(c_char)
d = test1(a, b, tstr)
print(b.values)
test1 有问题。 test2 成功运行。 原函数test1 n C为:
double testfun1(double x, double* y, char* str)
我希望函数的输出通过数组b恢复。 错误是:
ctypes.ArgumentError: argument 2: <class 'TypeError'>: expected LP_c_double instance instead of _ctypes.PyCPointerType
有人能帮帮我吗?
在 ctypes 中,POINTER(c_double)
是 class 表示指向 c_double
的指针。您要传递的不是 class 本身,而是 class 的一个实例。这就是您收到错误消息的原因,即 "expected an instance of 'pointer to double' instead of the type 'pointer to double'".
由于 C 函数的这些参数没有关联的大小,我假设它们是 in/out 参数,在这种情况下,您需要让它们指向真实的对象。这应该有效:
b = c_double()
c = c_char()
d = test1(a, byref(b), byref(c))
如果它们是数组,您可以在 Python 中创建数组,然后使用您找到的 POINTER
classes 创建实例:
DoublePointer = POINTER(c_double)
CharPointer = POINTER(c_char)
b = DoublePointer.from_buffer(some_array)
d = test1(a, b, tstr)
如果将C函数的参数声明为c_char_p
,则可以直接在其中使用Python字符串,而无需将它们显式转换为指针。
听起来 b
是一个数组,但 testfun1
没有得到数组大小的指示,问题中也没有提到它。下面是 testfun1
的一个示例实现,假设数组是三个元素:
test.c
#ifdef _WIN32
# define API __declspec(dllexport)
#else
# define API
#endif
#include <stdio.h>
API double testfun1(double x, double* y, char* str)
{
printf("%lf %p %s\n",x,y,str);
y[0] = x;
y[1] = x * 2;
y[2] = x * 3;
return x * 4;
}
这是调用它的 Python 代码:
test.py
from ctypes import *
dll = CDLL('test')
test1 = dll.testfun1
test1.argtypes = c_double,POINTER(c_double),c_char_p
test1.restype = c_double
a = 2.5
b = (c_double * 3)() # create an array of three doubles
s = b'test123'
d = test1(a,b,s)
print(d,list(b))
输出
2.500000 000001CA3E31B330 test123
10.0 [2.5, 5.0, 7.5]