我有以下C结构:
typedef struct { uint8_t a; uint8_t b; uint32_t c; uint8_t* d; }
使用ctypes,通过回调,我能够在Python中获得指向此类结构的指针,我们称之为ref。我可以这样轻松地获得a,b,c:
ref
from ctypes import cast, c_uint8, c_uint32, POINTER a = cast(ref, POINTER(c_uint8)).contents.value b = cast(ref + 1, POINTER(c_uint8)).contents.value c = cast(ref + 2, POINTER(c_uint32)).contents.value
但我无法从d读取字节。我尝试了以下方法:
d_pointer = cast(ref + 6, POINTER(POINTER(c_uint8))).contents first_byte_of_d = d_pointer.contents print type(first_byte_of_d) # prints <class 'ctypes.c_ubyte'> print first_byte_of_d
在最后一行,使用gdb调试时遇到了SIGSEGV。所以问题是,如何从Python中的结构访问指针的第一个字节?
你是假设c直接跟随b这是情况并非如此。编译器将在该结构中填充x86上的几个字节,以align c。
c
b
正确的方法是在中声明结构的一对一映射ctypes:
ctypes
from ctypes import * class object_t(Structure): _fields_ = [ ('a', c_uint8), ('b', c_uint8), ('c', c_uint32), ('d', POINTER(c_uint8)), ]
不,您可以获得任何以这种类型的成员的值。
C示例库:
#include <stdint.h> #include <stdlib.h> struct object_t { uint8_t a; uint8_t b; uint32_t c; uint8_t* d; }; static struct object_t object = {'a', 'b', 12345, NULL}; struct object_t * func1(void) { return &object; } void func2(void(*callback)(struct object_t *)) { callback(&object); }
从Python使用它:
from ctypes import * class object_t(Structure): _fields_ = [ ('a', c_uint8), ('b', c_uint8), ('c', c_uint32), ('d', POINTER(c_uint8)), ] callback_t = CFUNCTYPE(None, POINTER(object_t)) lib = CDLL('./file.dll') func1 = lib.func1 func1.argtypes = None func1.restype = POINTER(object_t) func2 = lib.func2 func2.argtypes = [callback_t] func2.restype = None ret = func1() a = ret.contents.a b = ret.contents.b c = ret.contents.c d = ret.contents.d def mycallback(obj): a = obj.contents.a b = obj.contents.b c = obj.contents.c d = obj.contents.d func2(callback_t(mycallback))