How to return array from C++ function to Python using ctypes
Question:
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?
Answers:
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()
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.
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?
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()
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.