Ctypes:获取结构体字段的指针

3
我需要获取一个指向结构体字段地址的指针。 重要提示:我正在为一组C结构体构建序列化器,因此我希望遍历结构体的字段并将每个字段的地址作为指针获取。 我知道有一种方法可以使用字段对象和它们的偏移属性来获取它们相对于结构体本身地址的偏移量,但这是一个通用指针。 您能否向我展示一种遍历结构体字段并为每个字段获取具有正确内部类型的ctypes指针的方法?
1个回答

6
这里是一种方法...
类变量Test._fields_定义了属性及其C类型。通过为字段赋值生成的类属性包含关于该属性偏移量的信息,例如:
>>> Test.a
<Field type=c_long, ofs=0, size=4>
>>> Test.b
<Field type=c_double, ofs=8, size=8>
>>> Test.c
<Field type=c_char_Array_10, ofs=16, size=10>

对于每种类型,from_buffer() 方法使用与现有类型相同的数据缓冲区构建 C 类型。结构的实例实现了访问其数据所需的缓冲区 API,因此如果您知道结构元素数据的偏移量,则可以生成引用相同数据的 ctypes 类型,并创建指向它的指针。
from ctypes import *

class Test(Structure):
    _fields_ = [('a',c_int),
                ('b',c_double),
                ('c',c_char * 10)]

x = Test(1,2.5,b'abc')

for field,ftype in Test._fields_:

    # Look up each attribute in the class, and get its offset.
    ofs = getattr(Test,field).offset

    # Create a pointer to the same field type using the same data.
    p = pointer(ftype.from_buffer(x,ofs))
    print(p,p.contents)

输出:

<__main__.LP_c_long object at 0x000001932DE0EEC8> c_long(1)
<__main__.LP_c_double object at 0x000001932DE0ECC8> c_double(2.5)
<__main__.LP_c_char_Array_10 object at 0x000001932DE0EDC8> <__main__.c_char_Array_10 object at 0x000001932DE0ECC8>

太棒了。谢谢! - alexroat
它能够工作是因为你正在迭代_fields_,这是一个Field对象列表,它具有正确的偏移量方法,对吧? - alexroat
我使用了_slots_,但它只包含字段的名称和类型,没有偏移方法。太好了! - alexroat
1
你可以从类属性本身中获得偏移量。 你可以从_fields_中获取属性列表。 我已经更新了回答,加入了更多的解释。 - Mark Tolonen
太棒了!这激发了我去看看:https://dev59.com/oqvka4cB1Zd3GeqPrVJz#50310152。 - CristiFati

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接