Python — функция ctypes c ++ возвращает массив неизвестного размера

У меня есть функция c ++, которая принимает указатель на массив известного размера в качестве входных данных и возвращает массив размера, который не может быть определен, пока функция не завершит свою обработку данных. Как я вызываю функцию c ++, передавая первый массив и получая результаты как второй массив?

В настоящее время я делаю что-то похожее на это:

ПИТОН:

def callout(largeListUlonglongs):
cFunc = PyDLL("./cFunction.dll").processNumbers

arrayOfNums = c_ulonglong * len(largeListUlonglongs)
numsArray = arrayOfNums()

for x in xrange(len(largeListUlonglongs)):
numsArray[x] = long(largeListUlonglongs[x])

cFunc.restype = POINTER(c_ulonglong * len(largeListUlonglongs))

returnArray = cFunc(byref(numsArray)).contents

return returnArray

Это работает до тех пор, пока returnArray имеет тот же размер, что и numsArray. Если он меньше, то пустые элементы массива заполняются нулями. Если возвращаемый массив больше, чем результаты, обрезаются после заполнения элементов массива.

Если это помогает, структура возвращаемого массива содержит размер возвращаемого массива в качестве его первого элемента.

Спасибо за помощь в продвижении…

2

Решение

Обычно предпочтительно, чтобы вызывающая сторона выделяла буфер. Таким образом, вызывающий абонент также может освободить его. Однако в этом случае только вызываемый абонент знает, как долго должен быть буфер. И поэтому бремя переходит к вызываемой стороне, чтобы выделить буфер.

Но это накладывает дополнительное ограничение на систему. Поскольку вызываемый объект выделяет буфер, вызывающий объект не может освободить его, если он не использует один и тот же распределитель. Это на самом деле может быть организовано без особых проблем. Вы можете использовать общий распределитель. Есть несколько. Ваша платформа выглядит как Windows, так что, например, вы можете использовать CoTaskMemAlloc а также CoTaskMemFree, Обе стороны интерфейса могут вызывать эти функции.

Альтернатива состоит в том, чтобы сохранить распределение и освобождение вместе. Вызывающий должен удерживать указатель, который возвращает вызываемый. Когда он заканчивает работу с буфером, обычно после копирования его в структуру Python, он просит библиотеку освободить память.

4

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

Дэвид дал вам полезный совет по вопросам управления памятью. Я обычно использовал бы более простую стратегию наличия функции в библиотеке для освобождения выделенного буфера. На вызывающем устройстве лежит ответственность за предотвращение утечек памяти.

Для меня ваш вопрос, кажется, просто о приведении результата к правильному типу указателя. Поскольку у вас есть длина в индексе 0, вы можете установить тип результата в long long указатель. Затем получите размер, чтобы вы могли привести результат к правильному типу указателя.

def callout(largeListUlonglongs):
cFunc = PyDLL("./cFunction.dll").processNumbers
cFunc.restype = POINTER(c_ulonglong)

arrayOfNums = c_ulonglong * len(largeListUlonglongs)
numsArray = arrayOfNums(*largeListUlonglongs)

result = cFunc(numsArray)
size = result[0]
returnArray = cast(result, POINTER(c_ulonglong * size))[0]

return returnArray
1