2009-09-09 17 views
15

Ich arbeite an einem Programm, wo ich einige Daten in einer Ganzzahl speichern und bitweise verarbeiten. Zum Beispiel könnte ich die Nummer 48 erhalten, die ich Stück für Stück bearbeiten werde. Im Allgemeinen hängt die Endianität von ganzen Zahlen von der Maschinendarstellung von Ganzzahlen ab, aber tut Python alles, um zu garantieren, dass die Ints immer Little-Endian sein werden? Oder muss ich Endianness wie in C prüfen und dann für beide Fälle einen eigenen Code schreiben?Endianness der ganzen Zahlen in Python

Ich frage, weil mein Code auf einem Sun-Rechner läuft und obwohl der, auf dem er läuft, jetzt Intel-Prozessoren verwendet, muss ich in Zukunft möglicherweise auf einen Rechner mit Sun-Prozessoren wechseln, von dem ich weiß, dass er Big-Endian ist.

Antwort

18

Pythons int hat die gleiche Endianness wie der Prozessor, auf dem es läuft. Mit dem Modul struct können Sie Byte-Blobs in Ints (und umgekehrt und einige andere Datentypen) auf native, Little-Endian- oder Big-Endian-Weise konvertieren, je nachdem, welche format string Sie gewählt haben: Starten Sie das Format mit @ oder keine Endianness Zeichen, um native Endiannität zu verwenden (und native Größen - alles andere verwendet Standardgrößen), '~' für native, '<' für little-endian, '>' oder '!' für Big-Endian.

Dies ist Byte für Byte, nicht Bit für Bit; Ich bin mir nicht sicher, was genau Sie meinen, wenn Sie in diesem Zusammenhang eine Bit-für-Bit-Verarbeitung durchführen, aber ich nehme an, es kann ähnlich behandelt werden.

Für schnelle „bulk“ Verarbeitung in einfachen Fällen beachten Sie auch die array Modul - die fromstring und tostring Methoden schnell auf große Anzahl von Bytes arbeiten können, und die byteswap Methode können Ihnen den „anderen“ Endian (native bekommen nicht-nativ oder umgekehrt), wiederum schnell und für eine große Anzahl von Elementen (das gesamte Array).

+0

es scheint wie Python ist immer Big Endian sogar auf Little-Endian-System. Bsp: print 0x0001 wird gedruckt 1 –

+3

@David 天宇 Wong, du zeichnest völlig ungerechtfertigte Abzüge von deiner Beobachtung - 0x0001 ist nur eine seltsam redundante hexadezimale Notation für Integer '1', nichts mit interner Repräsentation zu tun! –

+0

yup danke, ich habe mich mit all dem vermischt. Es scheint nur ein HEXSTRING einer ganzen Zahl zu sein. –

15

Wenn Sie Ihre Daten bitweise verarbeiten müssen, kann Ihnen das Modul bitstring behilflich sein. Es kann auch mit der Endianz zwischen den Plattformen umgehen (zumindest bei der letzten Trunk-Version - die in den nächsten Tagen veröffentlicht wird).

Die struct module ist die beste Standardmethode zum Umgang mit Endianess zwischen Plattformen. Zum Beispiel dieser Pack und entpacken Sie die ganzen Zahlen 1, 2, 3 in zwei ‚Shorts‘ und ein ‚long‘ (2 und 4 Bytes auf den meisten Plattformen) mit nativen endianness:

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

die endianness der Plattform Um zu überprüfen, programmatisch können Sie

>>> import sys 
>>> sys.byteorder 

verwenden, die entweder "big" oder "little" zurückkehren wird.

+0

Ich habe eine Menge ot diese Art von Erklärungen gesehen (auch cudo für sys.byteorder, wusste das nicht), aber ich muss fragen. Lets sagen, dass ich eine unbekannte Datei habe, die ich lesen möchte, wie kann ich wissen, ob einige Const Chars kurz oder lang und/oder groß und Little Endian sind? – Danilo

+1

@Danilo: Im Allgemeinen können Sie nicht sagen. Um ein unbekanntes Dateiformat zurückzuentwickeln, können Sie sich die Daten ansehen und erraten, welche Größe/Endianz am sinnvollsten ist. Zur Veranschaulichung, wenn Sie mein Beispiel mit der falschen Endianz entpacken, erhalten Sie (256, 512, 50331648) anstelle von (1, 2, 3) was ein vernünftiger Anhaltspunkt ist, dass Sie es falsch verstanden haben ... –

2

Prüfen wann?

Wenn Sie bitweise Operationen ausführen, hat der Int in die gleiche Endgültigkeit wie die eingegebenen Werte. Sie müssen das nicht überprüfen. Sie müssen sich nur darum kümmern, wenn Sie in/aus Sequenzen von Bytes in beiden Sprachen afaik konvertieren.

In Python verwenden Sie hierfür das struct-Modul, am häufigsten struct.pack() und struct.unpack().

+1

Es ist wichtig, weil ich es tue wie diese Dinge in meinem Code: wenn (a >> 2 & 1) ... elif (b >> 3 & 1) ... aber auf bigEndian würde ich wenn (a schreiben << 2 & 1) ... –

+0

@Gordon: Ich denke nicht, dass das richtig ist. Gibt es hier eine Verwechslung zwischen byteweise großer und kleiner Endianness und bitweise großer und kleiner Endianness? Wenn 'a' eine Ganzzahl ist, dann müssen Sie sich wahrscheinlich keine Gedanken über die Endianität machen, es ist nur eine Frage, wie Sie es aus rohen Byte-Daten erstellt haben. –

+0

@Gordon: Nein, würdest du nicht. Big/Small-Endian ändert nicht die Reihenfolge der Bits, sondern die Reihenfolge der * Bytes *. Die Shift-Operationen behandeln dies sowohl in Python als auch in C (da sie beide die Shift-Operationen der Prozessoren verwenden). –

1

Der folgende Ausschnitt wird Ihnen sagen, ob Ihr System Standard-Little-Endian ist

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

Beachten Sie jedoch (sonst ist es Big-Endian ist), wird dies nicht das Verhalten von Bit-Operatoren beeinflussen: 1<<1 gleich 2 unabhängig von der Standard-Endianz Ihres Systems.