【问题标题】:pass and return an array of doubles through c function inside Python通过 Python 中的 c 函数传递和返回一个双精度数组
【发布时间】:2019-11-14 23:05:06
【问题描述】:

我在 Python 代码中成功调用了一个 dll 库。所有的 By-Value 函数运行顺利。问题是我的 c 函数需要一个双精度数组的指针来返回结果。我不知道如何定义这个数组。

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

谁能帮帮我?

【问题讨论】:

  • 如果testfun1y中返回一个双精度数组,它怎么知道这个数组有多长?
  • 仅供参考,__getattr__ 并不意味着直接调用。请改用func = getattr(lib,funcname)

标签: python c pointers dll ctypes


【解决方案1】:

听起来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]

【讨论】:

  • 现在如果我想将数组 b b = (c_double * 3)() 中的一些数字传递给 test1.c 函数,我该怎么办?
  • @Ziyad 在创建b 时将数字作为参数传递,或者使用b[0] = ... 等设置它们。
【解决方案2】:

在 ctypes 中,POINTER(c_double) 是表示指向 c_doubles 的指针的类。你要传递的不是这个类本身,而是这个类的一个实例。这就是您收到错误消息的原因,它的意思是“期望一个 '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 字符串,而无需将它们显式转换为指针。

【讨论】:

  • 对不起。那没有用。它给了我错误。无论如何,我要感谢您花时间尝试解决此错误。
猜你喜欢
  • 1970-01-01
  • 2019-12-06
  • 2013-03-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-12-28
  • 2011-07-09
相关资源
最近更新 更多