2009-09-09 24 views
15

Estoy trabajando en un programa donde almaceno algunos datos en un entero y los proceso en bits. Por ejemplo, podría recibir el número 48, que procesaré bit a bit. En general, la endianidad de los enteros depende de la representación de la máquina de los enteros, pero ¿Python hace algo para garantizar que los ints siempre serán little-endian? ¿O necesito verificar endianness como lo haría en C y luego escribir un código separado para los dos casos?Endianness de enteros en Python

Lo pregunto porque mi código se ejecuta en una máquina Sun y, aunque la que se está ejecutando ahora usa procesadores Intel, podría tener que cambiar a una máquina con procesadores Sun en el futuro, que sé que es de gran tamaño.

Respuesta

18

Python's int tiene el mismo endianness que el procesador en el que se ejecuta. El módulo struct le permite convertir blobs de bytes en enteros (y viceversa, y algunos otros tipos de datos también) en formas nativas, little-endian o big-endian, según el format string que elija: inicie el formato con @ o sin endianness carácter para usar endianness nativo (y tamaños nativos - todo lo demás usa tamaños estándar), '~' para native, '<' para little-endian, '>' o '!' para big-endian.

Esto es byte a byte, no bit a bit; no estoy seguro de lo que quiere decir con el procesamiento bit por bit en este contexto, pero supongo que puede ser acomodado de manera similar.

Para una rápida "a granel" procesamiento en casos simples, tenga en cuenta también el módulo array - los métodos fromstring y tostring pueden operar en gran número de bytes con rapidez, y el método byteswap puede conseguir que el orden de bits "otro" (originaria de no nativo o viceversa), de nuevo rápidamente y para un gran número de elementos (toda la matriz).

+0

Parece que python siempre es un gran endian, incluso en el pequeño sistema endian. Ejemplo: imprimir 0x0001 imprimirá 1 –

+3

@David 天宇 Wong, está sacando deducciones completamente injustificadas de su observación - 0x0001 es solo una notación hexagonal extrañamente redundante para el entero '1', ¡nada que ver con la representación interna! –

+0

y gracias, me confundí con todo esto. Parece ser solo un HEXSTRING de un entero. –

15

Si necesita procesar sus datos 'bitwise', entonces el módulo bitstring podría serle útil. También puede tratar con endianness entre plataformas (al menos en la última construcción de troncales, que se lanzará en los próximos días).

El struct module es el mejor método estándar para tratar el endianismo entre plataformas. Por ejemplo, esto packs y desempaquetar los números enteros 1, 2, 3 en dos 'shorts' y uno 'de largo' (2 y 4 bytes en la mayoría de las plataformas) utilizando endianness nativo:

>>> from struct import * 
>>> pack('hhl', 1, 2, 3) 
'\x00\x01\x00\x02\x00\x00\x00\x03' 
>>> unpack('hhl', '\x00\x01\x00\x02\x00\x00\x00\x03') 
(1, 2, 3) 

Para comprobar el orden de bits de la plataforma mediante programación puede utilizar

>>> import sys 
>>> sys.byteorder 

que, o bien volver "big" o "little".

+0

He visto muchas explicaciones de este tipo (también cudo para sys.byteorder, no lo sabía) pero tengo que preguntar. Digamos que tengo un archivo desconocido que quiero leer, ¿cómo puedo saber si algunos caracteres de const son cortos o largos y/o grandes y poco endian? – Danilo

+1

@Danilo: en general, no se puede decir. Para realizar una ingeniería inversa de un formato de archivo desconocido, podría ver los datos y adivinar qué tamaño/endianness tenía más sentido. Para ilustrar, si descomprimes mi ejemplo con el endianness equivocado obtienes (256, 512, 50331648) en lugar de (1, 2, 3) que es una pista razonable de que lo has hecho mal ... –

2

Comprobar cuándo?

Al realizar operaciones a nivel de bit, la entrada tendrá la misma endiabilidad que las entradas que haya introducido. No necesita comprobarlo. Solo necesita importar esto al convertir a/desde secuencias de bytes, en ambos idiomas, afaik.

En Python utiliza el módulo struct para esto, normalmente struct.pack() y struct.unpack().

+1

Importa porque lo hago cosas en mi código como este: si (a >> 2 y 1) ... elif (b >> 3 y 1) ... sino en bigEndian que tendría que escribir si (a << 2 & 1) ... –

+0

@Gordon: No creo que sea correcto. ¿Existe alguna confusión aquí entre byte-wise big y little endianness y bit-wise big y little endianness? Si 'a' es un número entero, entonces probablemente no tenga que preocuparse por su endianidad, solo se trata de cómo lo creó a partir de los datos de bytes sin formato. –

+0

@Gordon: No, no lo harías. Big/small-endian no cambia el orden de los bits, sino el orden de * bytes *. Las operaciones de cambio manejan esto, tanto en Python como en C (ya que de hecho ambos usan las operaciones de cambio de los procesadores). –

1

El siguiente fragmento le dirá si su defecto del sistema es poco endian (de lo contrario es big-endian)

import struct 
little_endian = (struct.unpack('<I', struct.pack('=I', 1))[0] == 1) 

Tenga en cuenta, sin embargo, esto no afecta al comportamiento de los operadores de bits: 1<<1 es igual a 2 independientemente de la endianidad predeterminada de su sistema.