5

我必须将 Python 程序与 C 库连接起来。我需要调用的特定函数接受一个数组并返回一个双精度数。以下函数具有相同的签名,并且比我自己的更容易理解:

double sum(double * array, const int length) {
 double total = 0;
 int i;
 for (i=0; i<length; i++) {
     total += array[i];
 }
 return total;
}

我目前的解决方案是:

import ctypes
lib = ctypes.CDLL(library_name) 

l = 10
arr = tuple(range(l))

lib.sum.restype = ctypes.c_double
values = (ctypes.c_double * l)(*arr)
ret = lib.sum(values, l)

但是我在我的代码中经常使用数组模块,在我看来,将它们与 C 代码一起使用应该更直接,因为它是一个类型化的数组。所以我试图直接用一个数组来提供 C 函数,但它没有工作。为了使它工作,我像这样包装数组:

class Array(array):

   @property
   def _as_parameter_(self):
      return (TYPES[self.typecode] * len(self))(*self)

其中 TYPES 将类型代码从数组映射到 ctypes 类型:

   TYPES = {'c': ctypes.c_char,
            'b': ctypes.c_byte,
            'B': ctypes.c_ubyte,
            '?': ctypes.c_bool,
            'h': ctypes.c_short,
            'H': ctypes.c_ushort,
            'i': ctypes.c_int,
            'I': ctypes.c_uint,
            'l': ctypes.c_long,
            'L': ctypes.c_ulong,
            'q': ctypes.c_longlong,
            'Q': ctypes.c_ulonglong,
            'f': ctypes.c_float,
            'd': ctypes.c_double}

有没有办法用不创建另一个数组的东西替换 _as_parameter_ ?

谢谢

4

2 回答 2

4

使用 array.buffer_info() 获取地址和长度,并将地址 cast() 到 POINTER(c_double):

from array import array
buf = array("d", range(101))
addr, count = buf.buffer_info()
print lib.sum(cast(addr, POINTER(c_double)), count)
于 2012-05-17T00:56:00.523 回答
0

并不是说这是一个更好的答案,而是为了完整性,如果您使用的是numpy,它只是有点不同,因为 numpy 可以为您处理铸件。

import numpy as np
data = np.arange(101, dtype=ctypes.c_double) # making this match seems important sometimes
print lib.sum(data.ctypes.data_as(ctypes.POINTER(ctypes.c_double)), len(data))
于 2012-06-05T01:53:09.523 回答