pythonpython-cffi

using an int * (array) return value in python via cffi?


I have a C function

int * myfunc()
{
   int * ret = (int *) malloc(sizeof(int)*5);
   ...
   return ret;
}

in python I can call it as

ret = lib.myfunc()

but I can't seem to figure out how to actually use ret in the python code (i.e. cast it to an int array of length 5.

I see lots of documentation (and questions here) about how to pass a python array into a C function, but not how one deals with an array returned from a C function.

the only thing I've figured out so far (which sort of works, but seems ugly)

buf = ffi.buffer(ret,ffi.sizeof("int")*5)
int_array = ffi.from_buffer("int *", buf)

is that what I'm supposed to do? or is there a better way?


Solution

  • In C, the type int * and the type int[5] are equivalent at runtime. That means that although you get a int * from calling the function, you can directly use it as if it were a int[5]. All the same operations work with the exception of len(). For example:

    ret = lib.myfunc()
    my_python_list = [ret[i] for i in range(5)]
    lib.free(ret)    # see below
    

    As the function called malloc(), you probably need to call free() yourself, otherwise you have a memory leak. Declare it by adding the line void free(void *); to the cdef() earlier.

    There are some more advanced functions whose usage is optional here: you could cast the type from int * to int[5] with p = ffi.cast("int[5]", p); or instead you could convert the C array into a Python list with an equivalent but slightly faster call my_python_list = ffi.unpack(ret, 5).