我有以下C结构:
typedef struct {
uint8_t a;
uint8_t b;
uint32_t c;
uint8_t* d;
}
使用ctypes,通过回调,我能够在Python中获得指向这样一个结构的指针,让我们称之为ref
。我可以这样轻松地获得a,b,c:
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中的结构访问指针的第一个字节?
答案 0 :(得分:7)
您假设c
直接跟在b
之后,而事实并非如此。编译器将在该结构中填充x86上的几个字节,以对齐c
。
正确的方法是在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))