Python struct calsize与实际不同

Ivi*_*ony 5 python struct sizeof padding

我试图使用python从二进制文件中读取一个短和长struct.

但是

print(struct.calcsize("hl")) # o/p 16
Run Code Online (Sandbox Code Playgroud)

这是错误的,它应该是2个字节的短,8个字节的长.我不确定我struct是以错误的方式使用模块.

当我打印每个的值时

print(struct.calcsize("h")) # o/p 2
print(struct.calcsize("l")) # o/p 8
Run Code Online (Sandbox Code Playgroud)

有没有办法强制python保持精度datatypes

Sha*_*ger 3

默认结构对齐规则,16 是正确答案。每个字段都进行对齐以匹配其大小,因此最终会得到short两个字节的 a,然后是六个字节的填充(以到达与八个字节的倍数对齐的下一个地址),然后是八个字节的long.

您可以使用字节顺序前缀(其中任何一个都禁用填充),但它们也会禁用机器本机大小(因此struct.calcsize("=l")在所有系统上将是固定的 4 字节,并且struct.calcsize("=hl")在所有系统上将是 6 字节,而不是 10,即使在具有8 字节long)。

如果您想使用具有非默认填充规则的机器本机类型计算任意结构的结构大小,您需要转到模块,使用所需的设置ctypes定义您的子类,然后用于检查大小,例如:ctypes.Structure_pack_ctypes.sizeof

from ctypes import Structure, c_long, c_short, sizeof

class HL(Structure):
    _pack_ = 1  # Disables padding for field alignment
    # Defines (unnamed) fields, a short followed by long
    _fields_ = [("", c_short),
               ("", c_long)]

print(sizeof(HL))
Run Code Online (Sandbox Code Playgroud)

10根据需要输出。

如果需要,可以将其分解为实用函数(这是一个简化的示例,不处理所有struct格式代码,但您可以根据需要进行扩展):

from ctypes import *

FMT_TO_TYPE = dict(zip("cb?hHiIlLqQnNfd",
                       (c_char, c_byte, c_bool, c_short, c_ushort, c_int, c_uint,
                        c_long, c_ulong, c_longlong, c_ulonglong, 
                        c_ssize_t, c_size_t, c_float, c_double)))

def calcsize(fmt, pack=None):
    '''Compute size of a format string with arbitrary padding (defaults to native)'''
    class _(Structure):
        if pack is not None:
            _pack_ = pack
        _fields_ = [("", FMT_TO_TYPE[c]) for c in fmt]
    return sizeof(_)
Run Code Online (Sandbox Code Playgroud)

一旦定义,您就可以计算填充或未填充的大小,如下所示:

>>> calcsize("hl")     # Defaults to native "natural" alignment padding
16
>>> calcsize("hl", 1)  # pack=1 means no alignment padding between members
10
Run Code Online (Sandbox Code Playgroud)