Указатели и массивы в Python ctypes - PullRequest
35 голосов
/ 01 сентября 2009

У меня есть DLL, содержащая функцию C с прототипом, подобным этому:

int c_read_block(uint32 addr, uint32 *buf, uint32 num);

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

Создание массива и передача его "byref", например:

    cresult = (c_ulong * num)()
    err = self.c_read_block(addr, byref(cresult), num)

Дает это сообщение об ошибке:

ArgumentError: argument 3: <type 'exceptions.TypeError'>: expected LP_c_ulong instance instead of pointer to c_ulong_Array_2

Полагаю, это потому, что массив Python ulong не похож на массив c uint32. Должен ли я использовать create_char_string. Если да, то как мне убедить Python «привести» этот буфер к LP_c_ulong?

Ответы [ 3 ]

54 голосов
/ 01 сентября 2009

Вы можете кастовать с помощью функции cast:)

>>> import ctypes
>>> x = (ctypes.c_ulong*5)()
>>> x
<__main__.c_ulong_Array_5 object at 0x00C2DB20>
>>> ctypes.cast(x, ctypes.POINTER(ctypes.c_ulong))
<__main__.LP_c_ulong object at 0x0119FD00>
>>> 
1 голос
/ 24 августа 2018

Вы можете привести результат, но ctypes позволяет вам использовать массив вместо указателя, напрямую. Проблема заключается в byref в вашем коде (который будет эквивалентен указателю на указатель):

Так что вместо:

cresult = (c_ulong * num)()
err = self.c_read_block(addr, byref(cresult), num)

попробовать:

cresult = (c_ulong * num)()
err = self.c_read_block(addr, cresult, num)
0 голосов
/ 25 апреля 2016

В решении есть опечатка. Чтобы получить указатель на массив ulongs, вам необходимо привести к POINTER(list of ulong)

In [33]: ptr = ctypes.cast(x, ctypes.POINTER(ctypes.c_ulong*5))
In [34]: ptr
Out[34]: <__main__.LP_c_ulong_Array_5 at 0x23e2560>
...