2012-02-03 16 views
5

Estoy tratando de escribir un contenedor a una biblioteca nativa en Linux. Problema es el siguiente:python ctypes enviando puntero a la estructura como parámetro a la biblioteca nativa

definición en c:

int mymethod(mystruct* ptr)

en Python:

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

s = mystruct()

_lib.mymethod(ctypes.byref(s))
aumentos : Se espera LP_mystruct ejemplo, en lugar de puntero a myStruct

_lib.mymethod(ctypes.pointer(s))
plantea espera ejemplo LP_mystruct en lugar de LP_mystruct

errores. ¿Cómo pasar una estructura como un puntero a un método nativo?

Gracias.

Mete

Respuesta

5

El problema es que el nivel superior "PUNTERO" de ctypes es, en Python, un objeto diferente de "un puntero genérico" (ctypes.CArgObject por ctypes.byref) que se devuelve o un único número que representa una memoria dirección (que es lo que se devuelve por ctype de adrresof) - usted puede anotar su función para recibir una `ctypes.c_voidp y llamarlo con _lib.mymethod(ctypes.addressof(a)) lugar -

O si se quiere trabajar en el lado mecanografiado stronged-para evitar errores que haría crash Python (un error de tipo provoca una excepción de Python en su lugar; un parámetro incorrecto pasado a un C uncti on causaría una falla de segmentación en el intérprete de Python), debe crear una variable para contener el nuevo "tipo" que es un POINTER para su estructura, y luego crear una instancia de este tipo con la dirección de su estructura:

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

Gracias! Usé el segundo método que dijiste y funciona sin problemas. – mete

+0

algo similar aquí - https://codexample.org/questions/238108/python-ctypes-sending-pointer-to-structure-as-parameter-to-native-library.c –

+0

¿Cuál es el tipo de POINTER de nivel superior en ctypes ? –

3

(sé que esto es una vieja pregunta, pero creo que la respuesta aceptada es una solución innecesaria, por lo que quiero dejar esto aquí para la posteridad.)

ctypes en realidad debería explicitly support usando byref() para pasar un puntero como ese:

ctypes exporta la función byref() que se usa para pasar parámetros por referencia. Se puede lograr el mismo efecto con la función pointer(), aunque pointer() hace mucho más trabajo ya que construye un objeto puntero real, por lo que es más rápido usar byref() si no necesita el objeto puntero en Python.

La causa probable de esto es que usted ha definido su estructura en más de un lugar (p.ej. en diferentes módulos) - si la asignación argtypes ve una definición y la llamada a la función ve al otro, surge este confuso error. En otras palabras, ctypes intenta hacer coincidir dos tipos de mystruct que son (probablemente) idénticos en los contenidos, y tienen exactamente el mismo nombre, pero no son el mismo tipo.Siempre que el tipo de estructura base sea un objeto de tipo único, no importa si se construye un puntero usando pointer(), byref() o POINTER()() - ctypes detectará que el tipo subyacente (apuntado a) es el mismo.

Para verificar si este es el caso, pruebe assert(_lib.mymethod.argtypes[0]._type_ == type(s)) justo antes de llamar a la función externa.

Cuestiones relacionadas