2010-04-10 5 views
15

Python sagt, ich brauche 4 Bytes für einen Formatcode von "BH":struct.error: erfordert auspacken ein String-Argument der Länge 4

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

Hier wird der Code, ich in 3 Bytes als Ich stelle denken ist erforderlich: (!?)

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

"B" Unsigned char (1 Byte) + "H" Unsigned short (2 Byte) = 3 Bytes

struct.calcsize ("BH") sagt, 4 Bytes.

EDIT: Die Datei ist ~ 800 MB und das ist in den ersten paar Bytes der Datei, so dass ich ziemlich sicher bin, gibt es noch Daten zum Lesen.

Antwort

20

Das Strukturmodul ahmt C-Strukturen nach. Es dauert mehr CPU-Zyklen für einen Prozessor, um ein 16-Bit-Wort an einer ungeraden Adresse oder ein 32-Bit-Dword an einer nicht durch 4 teilbaren Adresse zu lesen, daher fügen Strukturen "Pad-Bytes" hinzu, um Strukturelemente auf natürliche Grenzen fallen zu lassen. Berücksichtigen Sie:

Diese Struktur belegt 12 Bytes des Arbeitsspeichers (x ist Pad Bytes).

Python funktioniert ähnlich (siehe struct Dokumentation):

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

Compiler hat in der Regel einen Weg Polsterung auszuschalten. In Python ist eines von = <>! wird Polsterung beseitigen:

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

Hüten Sie sich davor, lassen Struktur padding. In C sind diese Strukturen:

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

sind in der Regel 4 bzw. 8 Bytes. Die Auffüllung erfolgt am Ende der Struktur, falls die Strukturen in einem Array verwendet werden. Dies hält die "a" -Mitglieder an korrekten Grenzen für Strukturen später im Array ausgerichtet. Python-Struktur-Modul nicht Pad am Ende:

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

Ich frage mich, warum Python die Daten nicht in einem solchen Format packt. "01 01 00" gepackt Byte 0x01, kurz 0x01, aber es versucht es wie "01 00 01 00" auszupacken. Wie auch immer, ich habe mein Problem gelöst, ich füge immer '<' vor all meinen Formatcodes hinzu, um sie ungepolstert zu machen. Danke für die Erklärung. :) –

+0

hatte ein ähnliches Problem, das '=' noch '@' löste nicht ... mit Code, den ich auf Mac auf Windows – jokoon

+0

@ThomasO Warum sagst du es packt es als "01 01 00"? Ich sehe struct.pack ('BH', 1, 2) == '\ x01 \ x00 \ x02 \ x00'. – aij

6

Standardmäßig wird der Short auf vielen Plattformen mit einem Offset von einem Vielfachen von 2 ausgerichtet, sodass nach dem Zeichen ein Füllbyte hinzugefügt wird.

Um dies zu deaktivieren, verwenden Sie: struct.unpack("=BH", data). Dies wird Standardausrichtung verwenden, die nicht padding fügt:

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

Der = Charakter verwenden nativen Byteanordnung. Sie können auch < oder > anstelle von = verwenden, um die Little-Endian- bzw. Big-Endian-Byte-Reihenfolge zu erzwingen.

+0

Merkwürdig ist, sehe ich meine Datei in hex, und ich habe die Daten 01 01 00, die drei Bytes für die Version zeigt: einen einzigen ‚großen‘ Byte und ein Single 'Moll' kurz. Also ist die Aussage falsch? auspacken ("BH", pack ("BH", 3, 6)) == (3, 6) Danke für deine Hilfe. –

+0

@Thomas: Ich bin mir nicht sicher, was genau du fragst. Der von Ihnen gepostete Ausdruck wird als True ausgewertet. – interjay

+0

Das ist, was ich dachte, und es ist ziemlich genau das, was ich mache. Ich packe mit Python, einer einfachen Datenbank, mit pack ("BH", major_ver, minor_ver) und entpacke dann mit unpack ("BH"). Auf dem gleichen Computer, der ein Intel C2D x86-64 ist. Woher kommt das zusätzliche Byte?Ich werde = BH verwenden, aber mit dem Verdacht, dass irgendwo ein Byte verloren geht oder verloren geht. –