I am using ctypes to implement a C++ function in Python. The C++ function should return a pointer to an array. Unfortunately I haven't figured out, how to access the array in Python. I tried numpy.frombuffer, but that was not successful. It just returned an array of arbitrary numbers. Obviously I didn't used it correctly. Here is a simple example with an array of size 10:
Content of function.cpp:
extern "C" int* function(){ int* information = new int[10]; for(int k=0;k<10;k++){ information[k] = k; } return information; }
Content of wrapper.py:
import ctypes import numpy as np output = ctypes.CDLL('./library.so').function() ArrayType = ctypes.c_double*10 array_pointer = ctypes.cast(output, ctypes.POINTER(ArrayType)) print np.frombuffer(array_pointer.contents)
To compile the C++ file i am using:
g++ -c -fPIC function.cpp -o function.o g++ -shared -Wl,-soname,library.so -o library.so function.o
Do you have any suggestions what I have to do to access the array values in Python?
ctypes is a foreign function library for Python. It provides C compatible data types, and allows calling functions in DLLs or shared libraries. It can be used to wrap these libraries in pure Python.
Your python code will work after some minor modifications:
import ctypes f = ctypes.CDLL('./library.so').function f.restype = ctypes.POINTER(ctypes.c_int * 10) print [i for i in f().contents] # output: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
Basically there are two changes:
remove numpy-related code and ctypes.cast
call since we don't need them.
specify the return type to ctypes.POINTER(ctypes.c_int * 10)
.
By default foreign functions are assumed to return the C int type, hence we need change it to the desired pointer type.
BTW, returning a new
ed array from C code to Python code seems inappropriate. Who and when will free the memory? It's better to create arrays in Python code and pass them to C code. This way it's clear that the Python code owns the arrays and takes the responsibility of creating and reclaiming their spaces.
function.cpp
returns an int array, while wrapper.py
tries to interpret them as doubles. Change ArrayType
to ctypes.c_int * 10
and it should work.
It's probably easier to just use np.ctypeslib
instead of frombuffer
yourself. This should look something like
import ctypes from numpy.ctypeslib import ndpointer lib = ctypes.CDLL('./library.so') lib.function.restype = ndpointer(dtype=ctypes.c_int, shape=(10,)) res = lib.function()
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