I'm trying to get a test project working that calls a C function, with an array parameter, from Python:
test.cpp:
void testFn(int arr[]);
void testFn(int arr[])
{
    arr[0] = 1;
    arr[1] = 2;
} 
caller.pyx:
import ctypes
cdef extern from "test.cpp":
    void testFn(int arr[])
def myTest():
    a = [0, 0]
    arr = a.ctypes.data_as(ctypes.POINTER(ctypes.c_integer))
    testFn(arr)
    print(arr)
setup.caller.py:
from distutils.core import setup
from distutils.extension import Extension
from Cython.Distutils import build_ext
sourcefiles = ['caller.pyx']
ext_modules = [Extension("caller", sourcefiles)]
setup(
    name = 'test app',
    cmdclass = {'build_ext': build_ext},
    ext_modules = ext_modules
)
But when I try to build the project I get an error:
$ python setup.caller.py build_ext --inplace
running build_ext
cythoning caller.pyx to caller.c
Error compiling Cython file:
------------------------------------------------------------
...
def myTest():
    a = [0, 0]
    arr = a.ctypes.data_as(ctypes.POINTER(ctypes.c_integer))
    testFn(arr)
          ^
------------------------------------------------------------
caller.pyx:13:11: Cannot convert Python object to 'int *'
                This question pops up so often, but I was not able to find a good duplicate-target, which would go beyond "just do that and it will work".
This is a very usual situation: you try to pass some python data structures to c-code which expects pointers int *, double *,.... However pointers are not a python object, so we cannot pass them from/to python code.  
Cython can automatically handle conversion to int, double, float and so on, even char * (it is a null-terminated c-string) and some stl-containers, but not to pointers (char *being the one exception).
There are two most common situations:
array.array, numpy-arrays).list)1. Passing via memory-view:
There is no way in python we can somehow get hold of a pointer, so this must be done in cython. My first choice to pass an array.array or numpy.array (or any other python-object supporting buffer-protocol, for ctypes.Array see for example this SO-question) to a cython-function would be a memory-view:
def myTest(int[:] arr):
    testFn(&arr[0])
and now calling it from python:
>>> import array
>>> a=array.array('i', [0]*2)
>>> import caller
>>> caller.myTest(a)
>>> a
array('i', [1, 2]) #it worked
The following is important
int[:] is a python object (a typed memory view) so it can be passed to a python function (def or cpdef).&arr[0] is used to take the address of the buffer of the memory view. Its result is of type int *.array.array('I', [0]*2) to it, because it is not a int-memory-view but a unsigned int-memory-view.2. Passing non-continuous memory (e.g. lists):
There is more work with list and Co.: The information is not stored in plain c-arrays so we need to copy them first to a continuous memory, pass this temp variable to our c-code and copy the results back to list, our cython function could looks as follows
import array
def myTest2(lst):
    tmp=array.array('i', lst)
    myTest(tmp)
    lst.clear()
    lst.extend(tmp)
And now after reloading the caller module:
>>> lst=[0,0]
>>> caller.myTest2(lst)
[1, 2]
So, it is possible to pass the content of a list to a c-function, but basically you want to work with array.array or numpy.array if you need data-exchange with c-code.  
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