如何获取Python ctypes结构体成员类型大小以格式化十六进制输出?
问题根因定位
你之前调用sizeof报错的核心原因是字段解包逻辑存在偏差:
- ctypes结构体的
_fields_属性中,每个字段条目的固定格式为:普通字段是(字段名称, 类型类)的二元组,带位域的字段是(字段名称, 类型类, 位宽)的三元组。 - 你写的
for name, *dtype in self._fields_:语法,会把条目里第二个及之后的所有元素打包成元组赋值给dtype。比如遇到('a', c_uint16)这样的普通字段时,dtype拿到的是包含类型对象的元组(c_uint16,),并不是类型类本身。把元组传入sizeof方法,自然会触发this type has no size的报错。
修正实现方案
- 遍历字段时,直接从每个字段条目的固定索引位置取出对应的类型类对象,再传入
sizeof计算实际占用字节数。 - 十六进制格式化时,按照
1字节对应2个十六进制字符的规则计算输出宽度,通过f-string的动态宽度参数自动补全前导零。
修改后的可直接运行的完整代码如下:
from ctypes import * class Tracerec(BigEndianStructure): def __repr__(self): textlist = list() for field_entry in self._fields_: name = field_entry[0] field_type = field_entry[1] # 直接取类型对象计算大小,不会触发报错 byte_size = sizeof(field_type) value = getattr(self, name) if isinstance(value, int): # 每个字节对应2位十六进制,计算需要的总输出宽度 hex_format_width = byte_size * 2 textlist.append(f'{name}:0x{value:0{hex_format_width}x}') else: textlist.append(f'{name}:{value}') fulltext = ' '.join(textlist) return f'<{self.__class__.__name__}={fulltext}>' def __getitem__(self, i): if type(i)==str: return getattr(self, i) return getattr(self, self._fields_[i][0]) def __len__(self): return len(self._fields_) class Mystruct(Tracerec): _fields_ = [ ('a', c_uint16), ('b', c_uint16), ('c', c_uint32), ] buffer = b'\x01\x02\x03\x04\x00\x00\x05\x06' x = Mystruct.from_buffer_copy(buffer) print(x)
运行后输出完全匹配预期:
<Mystruct=a:0x0102 b:0x0304 c:0x00000506>
补充说明:哪怕是带位域的字段条目,比如定义
('flag', c_uint8, 3),上述逻辑依然可以正确计算类型大小并完成格式化,和常规的结构体打印逻辑保持一致。
内容的提问来源于stack exchange,提问作者mrkbutty
相关产品推荐
相关产品推荐

