Python struct calsize与实际不同

时间:2018-01-24 14:57:09

标签: python struct padding sizeof

我正在尝试使用python struct从二进制文件中读取一个short和long。

但是

print(struct.calcsize("hl")) # o/p 16

这是错误的,它应该是2个字节,简称为8个字节。我不确定我是以错误的方式使用struct模块。

当我打印每个值时,

print(struct.calcsize("h")) # o/p 2
print(struct.calcsize("l")) # o/p 8

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

2 个答案:

答案 0 :(得分:1)

这是doc所说的:

  

默认情况下,打包给定C结构的结果包括填充字节,以便维护所涉及的C类型的正确对齐;类似地,在拆包时考虑对齐。选择此行为,以便打包结构的字节与相应C结构的内存中的布局完全对应。要处理与平台无关的数据格式或省略隐式填充字节,请使用native大小和对齐而不是=大小和对齐

将其从标准更改为本机非常简单:您只需在格式字符前附加前缀print(struct.calcsize("=hl")) 即可。

struct.calcsize("lh")

修改

从原生模式到标准模式,一些默认大小已更改,您有两个选项:

  • 保持原生模式,但以这种方式切换格式字符:struct.calcsize("=hq")。在C中,甚至结构中变量的顺序也很重要。这里的填充是8个字节,这意味着每个变量必须以8个字节的倍数引用。

  • 使用标准模式的格式字符,所以:justify-content: space-between;

答案 1 :(得分:1)

默认情况下,结构对齐规则,16是正确的答案。每个字段都是对齐的,以匹配其大小,因此您最终得到一个short两个字节,然后六个字节的填充(到达下一个地址,对齐到八个字节的倍数),然后是8个字节的{ {1}}。

您可以使用byte order prefix(其中任何一个禁用填充),但他们禁用机器本机大小(因此long将在所有系统上固定4个字节,struct.calcsize("=l")在所有系统上都是6个字节,而不是10个,即使在8字节struct.calcsize("=hl") s的系统上也是如此。

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

_pack_

根据需要输出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))

如果需要,可以将其作为效用函数进行考虑(这是一个不处理所有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 packis not None:
            _pack_ = pack
        _fields_ = [("", FMT_TO_TYPE[c]) for c in fmt]
    return sizeof(_)