python - ctypes bigendianstruct Littlendianstruct 对单字节返回不同的结果

标签 python ctypes endianness

当使用具有大端和小端类型的 ctypes 和结构以及具有特定位长度的字段时,我看到了不同的结果。我希望字节中的位顺序对于两种字节顺序都是相同的,但结果提供了不同的答案。结果来自 intel 盒子上的 centos 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
>>>

最佳答案

对于两种字节序,字节内的位顺序并不相同 - 当然,在任何体系结构中,您将数字复制到字节中,您会得到相同的字节。并且在两种架构中,最低有效位被寻址为位“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),并执行引用此结构的所有数据复制其他结构。

此外,对整个事情进行大量测试:-)。

关于python - ctypes bigendianstruct Littlendianstruct 对单字节返回不同的结果,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42958961/

相关文章:

python - 开放堆栈。 "No valid host was found"对于 cirrOS 以外的任何图像

Python Ctypes : convert list of integers to array of shorts

python - 从 c 共享库访问 python ctypes 结构

python - 如何保存包含指针的 ctypes 对象

cuda - NVIDIA 的 GPU 是大端还是小端?

c++ - UTF-8、Unicode 以及机器如何解释字节?

java - 基于不同服务构建请求的最佳方式/模式

python - 如何动态关闭和开启电子邮件发送?

python - sklearn中VotingClassifier的继承

python - ctypes 如何推断传递的整数类型?