Как вернуть массив из функции C ++ в Python, используя ctypes

Я использую ctypes для реализации функции C ++ в Python. Функция C ++ должна возвращать указатель на массив. К сожалению, я не понял, как получить доступ к массиву в Python. Я попытался numpy.frombuffer, но это не удалось. Он просто возвратил массив произвольных чисел. Очевидно, я не использовал это правильно. Вот простой пример с массивом размером 10:

Содержание function.cpp:

extern "C" int* function(){
int* information = new int[10];
for(int k=0;k<10;k++){
information[k] = k;
}
return information;
}

Содержание 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)

Для компиляции файла C ++ я использую:

g++ -c -fPIC function.cpp -o function.o
g++ -shared -Wl,-soname,library.so -o library.so function.o

Есть ли у вас какие-либо предложения, что мне нужно сделать, чтобы получить доступ к значениям массива в Python?

19

Решение

function.cpp возвращает массив int, а wrapper.py пытается интерпретировать их как двойники. + Изменить ArrayType в ctypes.c_int * 10 и это должно работать.


Это, вероятно, проще использовать np.ctypeslib вместо frombuffer сам. Это должно выглядеть примерно так

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()
15

Другие решения

Ваш код Python будет работать после некоторых незначительных изменений:

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]

В основном есть два изменения:

  1. удалить код, связанный с NumPy и ctypes.cast звоните, так как они нам не нужны.

  2. укажите тип возвращаемого значения для ctypes.POINTER(ctypes.c_int * 10),

    По умолчанию предполагается, что внешние функции возвращают тип C int, поэтому нам нужно изменить его на нужный тип указателя.

Кстати, возвращая newМассив ed из кода C в код Python кажется неуместным. Кто и когда освободит память? Лучше создавать массивы в коде Python и передавать их в C-код. Таким образом, ясно, что код Python владеет массивы и берет на себя ответственность за создание и восстановление их пространства.

19

По вопросам рекламы [email protected]