2017-03-22 4 views
0

Je vois des résultats différents lorsque j'utilise ctypes et Structure (s) avec des types petits et grands endian-ness, et des champs avec des longueurs de bits spécifiques. Je m'attendrais à ce que le bit d'ordre dans un octet soit le même pour les deux endia-ness, mais les résultats fournissent des réponses différentes. Les résultats proviennent d'une distribution de centos 6.8 64 bits sur une boîte Intel.ctypes bigendianstructure littlendianstructure renvoie des résultats différents pour un seul octet

>>> 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, ce sont en effet des résultats non intuitifs Je me demande qui a downvoted la question. – jsbueno

Répondre

0

L'ordre de bits dans un octet n'est pas le même pour les deux boutisme - bien sûr, dans toute architecture, la copie d'un numéro dans un octet, vous revenez le même octet. Et dans les deux architectures, le bit le moins significatif est adressé en tant que bit "0". Puisque les données sont déplacées en octets, et ce n'est qu'une émulation, ces valeurs de bits ne sont en fait pas reflétées dans une architecture x86 en mémoire. Cela est valable pour les wat ctypes, et probablement, le code C que vous génèreriez en jouant avec ça.

Cependant, si vous subdivisez un octet dans les champs, la position relative de ces champs se reflète dans l'octet -

Vous pouvez vérifier que d'une manière plus facile en utilisant la ctypes.Union construction (de cette façon vous excluez également un rembourrage -bytes effets secondaires comme des causes possibles des chiffres que vous voyez):

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

Et sur la console interactive:

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 

Voyant que vous travaillez probablement sur du code pratique, et pas seulement en jouant, mon conseil serait de garder toutes les structures qui doivent gérer des champs sous-octets comme LittleEndianStructure, et de créer une Union avec une BigEndianStructure avec la même taille d'octet pour chaque fois que vous devez copier des octets à partir du tampon pour faire vos E/S. En d'autres termes, juste pour être sûr que tout est clair: toute manipulation de bits sub-octets est effectuée sur la structure déclarée comme LittleEndian. Ensuite, pour copier des données multi-octets vers et depuis cette structure, vous les mettez dans une union avec une autre structure qui n'a que des champs avec un nombre entier d'octets - et qui peut être déclaré BigEndian - et effectue toute la copie des données référençant cette autre structure.

Aussi, faites beaucoup de tests sur l'ensemble :-).