我正在尝试使用Python的struct模块解码来自GPS系统的一些二进制头文件。我有两种类型的标题,长和短,我有一个阅读下面每一个的例子:
import struct
import binascii
packed_data_short = binascii.unhexlify('aa44132845013b078575e40c')
packed_data_long = binascii.unhexlify('aa44121ca20200603400000079783b07bea9bd0c00000000cc5dfa33')
print packed_data_short
print len(packed_data_short)
sS = struct.Struct('c c c B H H L')
unpacked_data_short = sS.unpack(packed_data_short)
print 'Unpacked Values:', unpacked_data_short
print ''
print packed_data_long
print len(packed_data_long)
sL = struct.Struct('c c c B H c b H H b c H L L H H')
unpacked_data_long = sL.unpack(packed_data_long)
print 'Unpacked Values:', unpacked_data_long
在这两种情况下,我得到了我期望的长度 - 短标头为12个字节,长标头为28个字节。此外,所有字段都正确显示(据我所知,对于旧数据)是合理的值。到目前为止一切都很好。
我把它移到另一台计算机上(运行不同版本的Python - 2.7.6而不是2.7.11)并且我使用calcsize
得到不同的结构长度,并且尝试传递它的长度会出错我已经计算了,而另一个版本是满意的。现在短标头需要16个字节,而长标签需要36个字节。
如果我传递的金额较大,则要求查找大部分记录,直到“L”记录为止。在长示例中,第一个是预期的,但第二个应该只是0,不正确,因此后面的两个字段也是不正确的。根据函数想要的字节数,我注意到每个“L”都是4,实际上只是运行struct.calcsize('L')
我得到的长度是2.7.6,4是2.7.11 。这至少缩小了问题所在,但我不明白为什么会发生这种情况。
目前我正在将第二台计算机更新为Python 2.7.11(一旦我拥有它就会更新),但我在结构文档中找不到任何可能表明已对此进行更改的内容。有没有我明显错过的或者这只是一个版本问题?
我所指的文档是here。
编辑:关于OS的评论 - 一个是Windows 7的64位版本(按预期工作的那个),第二个是64位版本的Ubuntu 14.04。答案 0 :(得分:6)
这不是一个错误;见struct
documentation:
请注意
默认情况下,打包给定C结构的结果包括填充字节 为了保持所涉及的C类型的正确对齐; 类似地,在拆包时考虑对齐。这个 选择行为,以便打包结构的字节对应 完全对应于相应C结构的内存布局。至 处理与平台无关的数据格式或省略隐式填充字节, 使用标准大小和对齐而不是原生大小和对齐方式: 见Byte Order, Size, and Alignment for details.
要解码来自该GPS设备的数据,您需要在7.3.2.1. Byte Order, Size, and Alignment中所述的格式字符串中使用<
或>
。因为你让它在另一台机器上运行,我认为数据是小端格式的,如果你使用它可以移植它
sS = struct.Struct('<cccBHHL')
sL = struct.Struct('<cccBHcbHHbcHLLHH')
其大小始终为
>>> sS.size
12
>>> sL.size
28
他们为什么不同?您正在使用的原始计算机是Windows计算机或32位计算机,而远程计算机是64位* nix。在本机大小中,L
表示C编译器的类型unsigned long
。在32位Unixen和所有Windows版本中,这是32位宽。
在64位Unix中,x86上的标准ABI为LP64,这意味着long
和指针是64位宽。但是,Windows uses LLP64;那里只有long long
是64位;原因是很多代码甚至Windows API本身长期依赖long
正好是32位。
如果存在<
标志,则L
和I
都始终保证为32位。其他字段说明符没有问题,因为它们的大小在所有x86平台和操作系统上保持不变。