5

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

2 Answers 2

4

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)
Sign up to request clarification or add additional context in comments.

1 Comment

where is cast defined?
0

Not that this is a better answer but for completeness if you are using numpy it is just a bit different as numpy can handle the cast part for you.

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

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.