python的struct.pack

时间:2017-11-19 02:50:48

标签: python struct endianness

使用python的struct.pack打包字节时,我很惊讶虽然我的字节顺序是little-endian,但我的 bit 顺序看起来很大-endian。我最重要的字节出现在下面输出的右侧,但每个字节的最高有效位出现在左侧。 (我使用bitstring中的BitArray来显示这些位。)

In[23]: BitArray(struct.pack('B', 1)).bin
Out[23]:'00000001'
In[24]: BitArray(struct.pack('H', 1)).bin
Out[24]:'0000000100000000'
In[25]: sys.byteorder
Out[25]:'little'

这让我感到惊讶,因为我读了here"比特顺序通常遵循与给定计算机系统的字节顺序相同的字节顺序。也就是说,在大端系统中,最高有效位存储在最低位地址;在小端系统中,最低有效位存储在最低位地址。"

我是否正确地解释了我的位顺序与我的字节顺序相反?

另外,我知道您可以使用><更改字节顺序,但我想有可能无法更改位顺序?

编辑:对于上下文,我现在正在编写一个基于协议描述的ATI NetFT传感器的TCP通信的python实现,从第B-76页开始here 。但是,我在与各种传感器实现串行和网络通信的工作中经常出现同样的问题。在这种情况下,协议描述说的是:将字节16的第2位设置为1以偏置传感器,并且我发现python中的位0与控制偏置的位0不对应 - 字节中的位顺序似乎被翻转。

1 个答案:

答案 0 :(得分:4)

不,Python无法反转位顺序 - 但您不需要。这篇文章让你过于偏执; - )

字节顺序的字节顺序通常对软件不可见。例如,如果您读取C中的2字节短消息,则无论物理存储约定如何,底层硬件都会提供大端结果。无论存储的物理字节顺序如何,存储258(0x0102)并且您回读258。唯一可以区分的方法是在小于N个字节的块中读取(或写入)部分N字节值。这在网络协议和便携式存储格式中很常见,但在这些格式之外很少见。

同样,能够检测物理位顺序的字节顺序的唯一方法是,如果机器是位可寻址的,那么您可以直接读取一位。我不知道任何支持位寻址的当前机器,即使有这样的野兽,C也不支持直接的位级访问。如果您及时读取一个字节,硬件将再次以big-endian位顺序传送字节,而不管物理位存储顺序如何。

例如,如果您一次戳到位级串行端口,那么您需要知道特定硬件所需的约定。但是在这种情况下struct.pack()无论如何都是无用的 - 最小单位struct.pack()操纵是一个字节,而那个级硬件位级排序是不可见的。例如,无论您运行它的机器的位级字节顺序如何,您的struct.pack('B', 1)都将解压缩为1。

代码位

由于“一般原则”在这里似乎不够,并且没有特定的代码可供使用,这里有一些可能有用的代码。

如评论中所述,如果要反转字节的位顺序,最简单,最快捷的方法是预先计算256个项目的列表,将字节映射到其位反转值:

br = [int("{:08b}".format(i)[::-1], 2) for i in range(256)]
assert sorted(br) == list(range(256))

然后,例如,

>>> br[0], br[1], br[2], br[254], br[255]
(0, 128, 64, 127, 255)

如果您正在使用bytes个对象,.translate()方法可以使用此表(在将其转换为bytes对象后)以通过一次调用转换整个对象:< / p>

reverse_table = bytes(br)

然后,例如,

>>> original = bytes([0, 1, 2, 3, 254, 255])
>>> print([i for i in original.translate(reverse_table)])
[0, 128, 64, 192, 127, 255]

相反,如果您一次构建一个字节(如“将字节16的第2位设置为1”),您可以从一开始就以“反向顺序”(适当时)构建它们。要按LSB 0顺序构建一个字节,“设置位i”表示

byte |= 1 << i

要改为以MSB 0顺序构建一个字节,它是

byte |= 1 << (7-i)

但是如果不知道您正在使用的API的确切细节,以及您希望如何工作,那么就无法猜测您需要的精确代码。