Python ctypes отправка указателя на структуру в качестве параметра в нативную библиотеку - PullRequest
5 голосов
/ 03 февраля 2012

Я пытаюсь написать оболочку для нативной библиотеки в Linux. Проблема заключается в следующем:

определение в c:

int mymethod(mystruct* ptr)

в питоне:

_lib.mymethod.argtypes = (ctypes.POINTER(mystruct),)<br> _lib.mymethod.restype = ctypes.c_int

s = mystruct()

_lib.mymethod(ctypes.byref(s))
повышает: ожидаемый экземпляр LP_mystruct вместо указателя на mystruct

_lib.mymethod(ctypes.pointer(s))
повышает ожидаемый экземпляр LP_mystruct вместо LP_mystruct

ошибки. Как передать структуру как указатель на нативный метод?

Спасибо.

Мета

Ответы [ 2 ]

5 голосов
/ 03 февраля 2012

Проблема в том, что более высокий уровень "POINTER" из ctypes в Python является другим объектом, чем "универсальный указатель" (ctypes.CArgObject на ctypes.byref), который возвращается, или одно число, представляющее адрес памяти (что и возвращается ctype * adrresof) - вы можете либо аннотировать вашу функцию, чтобы получить `ctypes.c_voidp, и вместо этого вызывать ее с _lib.mymethod(ctypes.addressof(a)) -

, либо если вы хотите работать с типизированными шрифтамичтобы избежать ошибок, которые могут привести к сбою Python (вместо ошибки типа возникает исключение Python - неправильный параметр, передаваемый в функцию C, может вызвать ошибку сегментации самого интерпретатора Python), необходимо создать переменную для хранения нового типа"который является указателем на вашу структуру - а затем создайте экземпляр этого типа с адресом вашей структуры:

mystruct_pointer = ctypes.POINTER(mystruct)
_lib.mymethod.argtypes = (mystruct_pointer,)
_lib.mymethod.restype = ctypes.c_int

s = mystruct()

_lib.mymethod(mystruct_pointer.from_address(ctypes.addressof(s)))
3 голосов
/ 07 октября 2016

(я знаю, что это старый вопрос, но я думаю, что принятый ответ - это ненужный обходной путь, поэтому я хочу оставить его здесь для потомков.)

На самом деле ctypes должен явно поддерживать , используя byref() для передачи указателя, подобного этому:

ctypes экспортирует функцию byref(), которая используется для передачи параметров по ссылке. Тот же эффект может быть достигнут с помощью функции pointer(), хотя pointer() выполняет намного больше работы, поскольку создает реальный объект-указатель, поэтому быстрее использовать byref(), если вам не нужен объект-указатель в Python сам по себе.

Вероятная причина этого в том, что вы определили свою структуру более чем в одном месте (например, в разных модулях) - если присваивание argtypes видит одно определение, а вызов функции видит другое, возникает эта запутанная ошибка. Другими словами, ctypes пытается сопоставить два mystruct типа, которые (возможно) идентичны по содержанию и имеют одинаковое имя, но они не являются одинаковым типом. Поскольку базовый тип структуры является объектом одного типа, не имеет значения, создаете ли вы указатель на него с помощью pointer(), byref() или POINTER()() - ctypes обнаружит, что базовый (указываемый) тип такой же.

Чтобы проверить, так ли это, попробуйте assert(_lib.mymethod.argtypes[0]._type_ == type(s)) прямо перед вызовом внешней функции.

...