Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to return array from C++ function to Python using ctypes

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?

like image 756
dolby Avatar asked Feb 15 '13 02:02

dolby


People also ask

What is Ctypes array?

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.


2 Answers

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:

  1. remove numpy-related code and ctypes.cast call since we don't need them.

  2. 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 newed 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.

like image 136
Hui Zheng Avatar answered Sep 21 '22 13:09

Hui Zheng


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() 
like image 39
Danica Avatar answered Sep 18 '22 13:09

Danica