如何获取用于格式化十六进制输出的python ctypes结构成员的长度?

2024-09-20 00:03:15 发布

您现在位置:Python中文网/ 问答频道 /正文

使用此代码:

from ctypes import *
class Tracerec(BigEndianStructure):
    def __repr__(self):
        textlist = list()
        for name, *dtype in self._fields_:
            value = getattr(self, name)
            if type(value) == int: textlist.append(f'{name}:0x{value: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)
x

我得到这个输出:

<Mystruct=a:0x102 b:0x304 c:0x506>

但是我希望它格式化为ctypes字节长度,但是sizeof(dtype)只返回this type has no size。期望输出的示例:

<Mystruct=a:0x0102 b:0x0304 c:0x00000506>

Tags: namefromselffieldsreturnvaluedefbuffer
2条回答

下面是我的最终解决方案(希望如此),它也支持使用位大小,数组类型也将分解:

class Tracerec(BigEndianStructure):
    # do not define _fields_ in this parent class
    
    def _format_value(self, value, dtype):
        if isinstance(value, Array):
            # Use Array undocumented _type_:
            text = ','.join([ self._format_value(x, value._type_) for x in value ])
            return f'[{text}]'
        elif type(value) == int:
            size = sizeof(dtype) * 2   # size mutliply by byte width
            return f'0x{value:0{size}x}'
        else:
            return f'{value}'
    
    def _format_field(self, field):
        name, dtype, *bitsize = field
        value = getattr(self, name)
        return f'{name}:{self._format_value(value, dtype)}'

    def __repr__(self):
        text = ' '.join( [ self._format_field(x) for x in self._fields_ ] )
        return f'<{self.__class__.__name__}={text}>'
    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,14),
        ('c', c_uint32),
        ('d', c_uint16 * 3)
    ]

buffer = b'\x01\x02\x03\x04\x00\x00\x05\x06\x07\x07\x08\x08\x09\x09\0x0\0x0'
x = Mystruct.from_buffer_copy(buffer)
x

以及输出:

<Mystruct=a:0x0102 b:0x00c1 c:0x00000506 d:[0x0707,0x0808,0x0909]>

请尝试sizeof(*dtype)并向左填充0:

...
for name, *dtype in self._fields_:
    value = getattr(self, name)
    size = sizeof(*dtype) * 2
    if type(value) == int: textlist.append(f'{name}:0x{value:0{size}x}')
    ...

相关问题 更多 >