2017-03-22 11 views
0

ctypesと構造体を使用した場合、大きなエンディアンと小さなエンディアンの型、および特定のビット長のフィールドで異なる結果が表示されます。私は両方のエンディアンでバイトの順序が同じであると期待しますが、結果は異なる答えを提供しています。結果は、インテルボックス上のcentos 6.8 64ビットディストリビューションからのものです。ctypes bigendianstructure littlendianstructureが1バイトで異なる結果を返す

>>> 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

Meh、これは本当に直感的ではない結果です。 – jsbueno

答えて

0

バイト内のビットの順序は、両方のエンディアンのために同じではありません - もちろん、任意のアーキテクチャでは、バイトに番号をコピーし、あなたは同じバイトを取り戻します。どちらのアーキテクチャにおいても、最下位ビットはビット "0"として扱われます。データはバイト単位で移動されるため、これはちょうどエミュレーションです。とにかく、これらのビット値はメモリ内のx86アーキテクチャに実際に反映されません。これはワットタイプに有効であり、おそらく、それと一緒に演奏するCコードです。

あなたはフィールド内のバイトを細分場合は、これらのフィールドの相対位置がバイト内ミラーリングされている -

あなたは簡単な方法でctypes.Union構文を使用していることを確認することができます(あなたはまた、詰め物を排除し、そのようあなたが見る数字の原因として-bytes副作用):

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 

あなたが実際にいくつかの実用的なコードに取り組んでいることを見て、単に演奏するのではなく、サブバイトフィールドをLitt​​leEndianStructureとして扱う必要があるすべての構造体を保持し、バッファからI/Oを行うためにバイトをコピーする必要があるときはいつでも。

別の言い方をすれば、リトルエンディアンとして宣言された構造体に対してすべてのサブバイトのビット操作が実行されることがわかります。次に、この構造体との間でマルチバイトデータをコピーするには、整数バイト数のフィールドしか持たず、BigEndianとして宣言できる構造体を持つ構造体をユニオンに入れ、これを参照するデータのコピーをすべて実行します他の構造。

また、全体的に多くのテストを行います:-)。

関連する問題