I have to interface a Python program with a C library. The particular function I need to call takes an array and returns a double. The following function has the same signature and is easier to understand than my own:
double sum(double * array, const int length) {
double total = 0;
int i;
for (i=0; i<length; i++) {
total += array[i];
}
return total;
}
My current solution is:
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)
But I use the array module a lot in my code and it seemed to me that using them with the C code should be more straight forward as it is a typed array. So I tried to feed the C function directly with an array but it did not work. To make it work, I wrapped array like this:
class Array(array):
@property
def _as_parameter_(self):
return (TYPES[self.typecode] * len(self))(*self)
where TYPES map the typecode from the array to ctypes types:
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}
Is there a way to replace _as_parameter_ by something that does not create another array?
Thanks
use array.buffer_info() to get the address and length, and cast() the address to 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)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With