2012-02-03 18 views
5

Próbuję napisać wrapper do rodzimej biblioteki w Linuksie. Problem jest następujący:Python ctypes wysyłający wskaźnik do struktury jako parametr do biblioteki natywnej

definicja c:

int mymethod(mystruct* ptr)

w Pythonie:

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

s = mystruct()

_lib.mymethod(ctypes.byref(s))
podbicia : Oczekuje LP_mystruct przykład zamiast wskaźnika do mystruct

_lib.mymethod(ctypes.pointer(s))
podnosi spodziewać LP_mystruct instancji zamiast LP_mystruct

błędów. Jak przekazać strukturę jako wskaźnik do metody natywnej?

Dzięki.

Mete

Odpowiedz

5

Problemem jest to, że wyższy poziom „wskaźnik” od ctypes jest pythonowa innego obiektu niż „ogólny wskaźnik” (ctypes.CArgObject przez ctypes.byref), który jest zwrócony lub pojedynczą liczbę reprezentującą pamięć adres (czyli to, co jest zwracane przez ctype na adrresof) - można też opisywać swoją funkcję, aby otrzymać `ctypes.c_voidp i wywołać ją z _lib.mymethod(ctypes.addressof(a)) zamiast -

Lub jeśli chcesz pracować na stronged wpisany boku, aby uniknąć błędów, które crash Python (błąd typu wywołuje wyjątek Pythona - nieprawidłowy parametr przekazany do C uncti on spowodowałby błąd segmentacji samego interpretera Pythona), musisz utworzyć zmienną, która będzie utrzymywać nowy "typ", który jest POINTERem do twojej struktury - a następnie utworzyć instancję tego typu z adresem twojej struktury:

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))) 
+1

Dzięki! Użyłem drugiej metody, którą powiedziałeś i działa bez problemu. – mete

+0

coś podobnego tutaj - https://codexample.org/pytania/238108/python-ctypes-sending-pointer-to-structure-as-parametr-to-native-library.c –

+0

Który jest wyższy poziom typ POINTER w ctypes ? –

3

(wiem, że jest to stara sprawa, ale myślę, że przyjęte rozwiązanie jest niepotrzebne obejście, więc chcę zostawić to tutaj dla potomności.)

Właściwie ctypes powinny explicitly support użyciu byref() zdać wskaźnik taki:

ctypes eksportuje funkcję byref(), która jest używana do przekazywania parametrów przez odniesienie. Ten sam efekt można osiągnąć za pomocą funkcji pointer(), chociaż pointer() wykonuje o wiele więcej pracy, ponieważ konstruuje obiekt rzeczywistego wskaźnika, więc szybciej jest użyć byref(), jeśli nie potrzebujesz obiektu wskaźnika w samym Pythonie.

prawdopodobną przyczyną jest to, że zostały zdefiniowane swoje struct w więcej niż jednym miejscu (na przykład w różnych modułów) - jeśli przydział argtypes widzi jedną definicję i wywołanie funkcji widzi drugi nasuwa to mylące błąd. Innymi słowy, ctypes próbuje dopasować dwa typy, które są (prawdopodobnie) identyczne pod względem treści i mają dokładnie taką samą nazwę, ale nie są one tym samym typem .Tak długo, jak podstawowy typ struktury jest obiektem pojedynczego typu, nie ma znaczenia, czy skonstruujemy wskaźnik do niego przy użyciu pointer(), byref() lub POINTER()() - ctypes wykryje, że podstawowy (wskazany) typ jest taki sam.

Aby sprawdzić, czy tak jest, spróbuj najpierw przed wywołaniem funkcji zewnętrznej assert(_lib.mymethod.argtypes[0]._type_ == type(s)).

Powiązane problemy