2010-04-10 8 views
15

Python dice que necesito 4 bytes para un código de formato de "BH":struct.error: requiere de desempaquetado un argumento de cadena de longitud 4

struct.error: unpack requires a string argument of length 4 

Aquí está el código, que estoy poniendo en 3 bytes como yo pensar se necesita: (!?)

major, minor = struct.unpack("BH", self.fp.read(3)) 

"B" char sin signo (1 byte) + "H" short sin signo (2 bytes) = 3 bytes

struct.calcsize ("BH") dice 4 bytes.

EDITAR: El archivo tiene ~ 800 MB y está en los primeros bytes del archivo, así que estoy bastante seguro de que aún quedan datos por leer.

Respuesta

20

El módulo struct imita las estructuras en C. Se requieren más ciclos de CPU para que un procesador lea una palabra de 16 bits en una dirección impar o una dword de 32 bits en una dirección no divisible por 4, por lo que las estructuras agregan "bytes de pad" para hacer que los miembros de la estructura caigan en límites naturales. Considere:

struct {     11 
    char a; 
    short b;  ------------ 
    char c;  axbbcxxxdddd 
    int d; 
}; 

Esta estructura ocupará 12 bytes de memoria (siendo x bytes de pad).

Python funciona de manera similar (véase la documentación struct):

>>> import struct 
>>> struct.pack('BHBL',1,2,3,4) 
'\x01\x00\x02\x00\x03\x00\x00\x00\x04\x00\x00\x00' 
>>> struct.calcsize('BHBL') 
12 

Los compiladores suelen tener una forma de eliminar el relleno. En Python, cualquiera de = <>! eliminará el relleno:

>>> struct.calcsize('=BHBL') 
8 
>>> struct.pack('=BHBL',1,2,3,4) 
'\x01\x02\x00\x03\x04\x00\x00\x00' 

Tenga cuidado con dejar que struct maneje el relleno. En C, estas estructuras:

struct A {  struct B { 
    short a;   int a; 
    char b;   char b; 
};    }; 

son típicamente 4 y 8 bytes, respectivamente. El relleno se produce al final de la estructura en caso de que las estructuras se utilicen en una matriz. Esto mantiene a los miembros 'a' alineados en los límites correctos para estructuras posteriores en el conjunto. módulo struct de Python no hace almohadilla al final:

>>> struct.pack('LB',1,2) 
'\x01\x00\x00\x00\x02' 
>>> struct.pack('LBLB',1,2,3,4) 
'\x01\x00\x00\x00\x02\x00\x00\x00\x03\x00\x00\x00\x04' 
+1

Lo que me pregunto es por qué Python no empaquetó los datos en ese formato en primer lugar. "01 01 00" empaquetó el byte 0x01, el corto 0x01, pero está tratando de descomprimirlo como "01 00 01 00". De todos modos, resolví mi problema, siempre estoy agregando '<' antes de todos mis códigos de formato, para que sean poco endian poco acolchados. Gracias por la explicación. :) –

+0

tuvo un problema similar, el '=' ni '@' no resolvió ... usando el código que hice en mac en Windows – jokoon

+0

@ThomasO ¿Por qué dices que está empaquetado como "01 01 00"? Estoy viendo struct.pack ('BH', 1, 2) == '\ x01 \ x00 \ x02 \ x00'. – aij

6

De forma predeterminada, en muchas plataformas, el corto se alineará con un desplazamiento en un múltiplo de 2, por lo que se agregará un byte de relleno después del carácter.

Para desactivar esto, use: struct.unpack("=BH", data). Esto utilizará la alineación estándar, que no añade el relleno:

>>> struct.calcsize('=BH') 
3 

El carácter = utilizará el orden de bytes nativo. También puede usar < o > en lugar de = para forzar el orden de bytes little-endian o big-endian, respectivamente.

+0

Curiosamente, miro a mi archivo en hexadecimal, y tengo los datos 01 01 00 que muestra tres bytes para la versión: un solo byte 'mayor' y una solo corto 'menor'. Entonces, ¿la afirmación es falsa? desempaquetar ("BH", paquete ("BH", 3, 6)) == (3, 6) Gracias por su ayuda. –

+0

@Thomas: No estoy seguro de qué es exactamente lo que estás preguntando. La expresión que publicaste se evaluará como Verdadero. – interjay

+0

Eso es lo que pensé, y es más o menos lo que estoy haciendo. Estoy empaquetando, usando Python, una base de datos simple, con paquete ("BH", major_ver, minor_ver), luego desempaquetando usando unpack ("BH"). En la misma computadora que es un Intel C2D x86-64. ¿Dónde entra el byte extra?Usaré = BH, pero con alguna sospecha de que un byte se está perdiendo o ganando en alguna parte. –

Cuestiones relacionadas