通过Python中的c函数传递并返回一个双精度数组

时间:2019-07-04 08:46:48

标签: python c pointers dll ctypes

我在Python代码中成功调用了dll库。所有“按值”功能均正常运行。问题是我的c函数需要doubles数组的指针才能返回结果。我不知道如何定义此数组。

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

有人可以帮助我吗?

2 个答案:

答案 0 :(得分:0)

在ctypes中,POINTER(c_double)是表示指向c_double的指针的类。您要传递的不是该类本身,而是该类的实例。这就是为什么您收到错误消息的原因,该错误消息的意思是“预期的实例为'pointer to double'而不是'pointer to double'类型”。

由于C函数的这些参数没有关联的大小,因此我将假定它们是输入/输出参数,在这种情况下,您需要使它们指向实际对象。这应该起作用:

b = c_double()
c = c_char()
d = test1(a, byref(b), byref(c))

如果它们是数组,则可以在Python中创建数组,然后使用发现的POINTER类创建实例:

DoublePointer = POINTER(c_double)
CharPointer = POINTER(c_char)
b = DoublePointer.from_buffer(some_array)
d = test1(a, b, tstr)

如果将C函数的参数声明为c_char_p,则可以直接在其中使用Python字符串,而不必将它们显式转换为指针。

答案 1 :(得分:0)

听起来=ARRAYFORMULA(IFERROR(VLOOKUP(A3:A, {Sheet1!B:H; Sheet1!I:O; Sheet1!P:V; Sheet1!W:AC; Sheet1!AD:AJ; Sheet1!AK:AQ}, {3, 4, 5, 7}, 0))) 是一个数组,但是b并没有指示该数组的大小,问题中没有提到。这是testfun1的示例实现,其中假定数组是三个元素:

test.c

testfun1

这是调用它的Python代码:

test.py

#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;
}

输出

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))