2013-04-15 2 views
2

У меня есть функция C++, которая принимает указатель на массив известного размера как входной и возвращает массив размера, который не может быть определен до тех пор, пока функция не завершит обработку данных. Как я могу вызвать функцию C++, передав первый массив и получив результаты как второй массив?ctypes Функция 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. Если он меньше, то пустые элементы массива заполняются 0. Если возвращаемый массив больше, чем результаты будут обрезаны после заполнения элементов массива.

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

Спасибо за помощь заранее ...

+0

* «Если он меньше, то пустые элементы массива заполняются 0». * Это чистое совпадение, основанное на том, выделена ли эта память и нуль. Это может быть так же легко segfault. ctypes не копирует возвращаемый массив в новый буфер. – eryksun

ответ

4

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

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

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

1

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

Мне кажется, что ваш вопрос просто о том, чтобы привести результат к правильному типу указателя. Поскольку у вас есть длина в индексе 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 
Смежные вопросы