ctypes bigendianstructure littlendianstructure为单字节返回不同的结果

时间:2017-03-22 17:39:22

标签: python ctypes endianness

当使用具有大端和小端字节类型的ctypes和Structure以及具有特定位长度的字段时,我看到了不同的结果。我希望一个字节中的位排序对于两个endia-ness都是相同的,但结果提供了不同的答案。结果来自英特尔盒子上的一个6.8位64位发行版。

>>> import ctypes
>>>
>>> class header_struct(ctypes.Structure):
...       _fields_ = [ ('f1',ctypes.c_ubyte,4),
...                    ('f2',ctypes.c_ubyte,4) ]
...
>>> class header_struct_be(ctypes.BigEndianStructure):
...       _fields_ = [ ('f1',ctypes.c_ubyte,4),
...                    ('f2',ctypes.c_ubyte,4) ]
...
>>> class header_struct_le(ctypes.LittleEndianStructure):
...       _fields_ = [ ('f1',ctypes.c_ubyte,4),
...                    ('f2',ctypes.c_ubyte,4) ]
...
>>> a='\x0A'
>>> x=header_struct.from_buffer_copy(a)
>>> x_be=header_struct_be.from_buffer_copy(a)
>>> x_le=header_struct_le.from_buffer_copy(a)
>>>
>>> print " sizeof(x) ", ctypes.sizeof(x)
 sizeof(x)  1
>>> print " sizeof(x_be) ", ctypes.sizeof(x_be)
 sizeof(x_be)  1
>>> print " sizeof(x_le) ", ctypes.sizeof(x_le)
 sizeof(x_le)  1
>>>
>>> x.f1
10
>>> x_be.f1
0
>>> x_le.f1
10
>>>
>>>
>>> x.f2
0
>>> x_be.f2
10
>>> x_le.f2
0
>>>

1 个答案:

答案 0 :(得分:0)

字节内的位顺序对于两个字节序都不一样 - 当然,在任何架构中,你将一个数字复制到一个字节中,你得到相同的字节。在这两种体系结构中,最低有效位被称为bit" 0"。由于数据以字节为单位移动,这只是模拟,无论如何这些位值实际上并未在内存中的x86架构中进行镜像。这对于wat ctypes是有效的,并且可能是你生成的C代码和它一起播放。

但是,如果在字段中细分一个字节,这些字段的相对位置会在字节内镜像 -

您可以使用ctypes.Union构造以更简单的方式检查它(这样您也可以排除填充字节副作用,因为可能会导致您看到的数字):

import ctypes
class header_struct(ctypes.Structure):
       _fields_ = [ ('f1',ctypes.c_ubyte,4),
                  ('f2',ctypes.c_ubyte,4) ]

class big_endian(ctypes.BigEndianStructure):
      _fields_ = [ ('b{}'.format(i), ctypes.c_ubyte, 1) for i in range(8) ]
class little_endian(ctypes.LittleEndianStructure):
      _fields_ = [ ('b{}'.format(i), ctypes.c_ubyte, 1) for i in range(8) ]

class le_byte(ctypes.LittleEndianStructure):
    _fields_ = [('value', ctypes.c_ubyte)]

class be_byte(ctypes.BigEndianStructure):
    _fields_ = [('value', ctypes.c_ubyte)]

class Union(ctypes.Union):
    _fields_ = [('le', le_byte), ('be', be_byte), ('lebits', little_endian), ('bebits', big_endian)]

在交互式控制台上:

In [319]: u = Union()

In [320]: u.le.value = 0x80

In [321]: u.be.value  # not mirrored
Out[321]: 128

In [322]: u.lebits.b7 
Out[322]: 1

In [323]: u.lebits.b0
Out[323]: 0

In [324]: u.bebits.b7
Out[324]: 0

In [325]: u.bebits.b0
Out[325]: 1

看到你可能正在研究一些实用的代码,而不只是一起玩,我的建议是将所有必须处理子字节字段的结构保持为LittleEndianStructure,并创建一个具有相同字节的BigEndianStructure的Union -size,无论何时你必须从缓冲区复制字节来进行I / O.

换句话说,只是为了确保它是明确的:所有子字节位操作都在声明为LittleEndian的结构上执行。然后,要将多字节数据复制到此结构或从此结构复制多个字节数据,请将其与另一个只包含整数字节数的结构放在一个联合中 - 并且可以将其声明为BigEndian - 并执行引用此操作的所有数据复制其他结构。

另外,对整个事情做了很多测试:-)。