Angenommen, ich habe die Nummer 'numb'=1025 [00000000 00000000 00000100 00000001] repräsentiert:
Auf Little-Endian-Maschine:
00000001 00000100 00000000 00000000
Auf Big-Endian-Maschine:
00000000 00000000 00000100 00000001
Wenn ich nun die Linksverschiebung auf 10 Bits anwende (dh: numb <<= 10), sollte ich Folgendes haben:
[A] Auf Little-Endian-Maschine:
Wie ich in GDB bemerkt habe, macht Little Endian die Linksverschiebung in 3 Schritten: [I have shown ‘3’ Steps to better understand the processing only]
Behandle die Nr. in Big-Endian-Konvention:
00000000 00000000 00000100 00000001
Links-Shift anwenden:
00000000 00010000 00000100 00000000
Stellen Sie das Ergebnis wieder in Little-Endian dar:
00000000 00000100 00010000 00000000
[B]. Auf Big-Endian-Maschine:
00000000 00010000 00000100 00000000
Meine Frage ist:
Wenn ich direkt eine Linksverschiebung auf die Little-Endian-Konvention anwende, sollte es Folgendes geben:
numb:
00000001 00000100 00000000 00000000
numb << 10:
00010000 00000000 00000000 00000000
Aber eigentlich gibt es:
00000000 00000100 00010000 00000000
Um nur das zweite Ergebnis zu erzielen, habe ich oben drei hypothetische Schritte gezeigt.
Bitte erklären Sie mir, warum die beiden obigen Ergebnisse unterschiedlich sind: Das tatsächliche Ergebnis von numb << 10 ist anders als das erwartete Ergebnis.
Carl
Endianness ist die Art und Weise, wie Werte im Speicher gespeichert werden. Wenn sie in den Prozessor geladen wird, arbeitet die Bitverschiebungsinstruktion ungeachtet der Endianness mit dem Wert im Register des Prozessors. Daher ist das Laden vom Speicher in den Prozessor das Äquivalent zum Konvertieren in Big Endian, die Verschiebungsoperation kommt als nächstes und dann wird der neue Wert zurück in den Speicher gespeichert, wo die Byte-Reihenfolge Little Endian wieder wirksam wird.
Update, danke an @jww: Auf PowerPC sind die Vektorverschiebungen und -drehungen Endian-sensitiv. Sie können einen Wert in einem Vektorregister haben und eine Verschiebung führt zu unterschiedlichen Ergebnissen bei Little-Endian und Big-Endian.
Danke für die Erklärung. Können Sie mir bitte eine Referenz vorschlagen, wo ich solche Feinheiten besser verstehen kann.
Mein Code funktioniert also unabhängig von Endian?! das ist toll! Ich war SO besorgt, dass ich meinen Code bis zur Hölle und zurück hacken müsste!
– MarcusJ
2. Mai 2016 um 5:00 Uhr
@MarcusJ: Nicht unbedingt. Wenn Sie beispielsweise 4 Bytes aus einer Datei lesen, die eine 32-Bit-Ganzzahl darstellen, müssen Sie die Endianness der gelesenen Daten in Verbindung mit der Endianness des Systems berücksichtigen, das die Daten empfängt, um sie richtig zu interpretieren die Daten.
– Carl
2. Juni 2016 um 6:52 Uhr
Auf PowerPC sind die Vektorverschiebungen und -drehungen Endian-empfindlich. Sie können einen Wert in einem Vektorregister haben und eine Verschiebung führt zu unterschiedlichen Ergebnissen bei Little-Endian und Big-Endian.
– jww
14. März 2018 um 16:55 Uhr
Nein, Bitshift ist wie jeder andere Teil von C in Bezug auf definiert Werte, keine Darstellungen. Linksverschiebung um 1 ist Multiplikation mit 2, Rechtsverschiebung ist Division. (Wie immer, wenn Sie bitweise Operationen verwenden, achten Sie auf Vorzeichen. Bei ganzzahligen Typen ohne Vorzeichen ist alles am besten definiert.)
Dies gilt grundsätzlich für ganzzahlige Arithmetik, aber C bietet viele Fälle von darstellungsabhängigem Verhalten.
– Edmund
25. August 2011 um 3:44 Uhr
@Edmund: Hm … vor allem ist die Implementierung der Vorzeichen nicht angegeben, und als Folge davon ist das Verhalten von bitweisen Operationen (wie Rechtsverschiebung) und von Modulo und Division eine Implementierung, die für negative Ganzzahlen definiert ist. Welche anderen Dinge haben Sie im Sinn, die von der Implementierung bestimmt werden?
– Kerrek SB
25. August 2011 um 10:24 Uhr
@KerrekSB leider sind sie nicht für negative Ganzzahlen implementiert. Sie sind in C89 nicht spezifiziert und in C99+ nicht definiert, was eine sehr schlechte Idee war.
– Paolo Bonzini
1. Januar 2016 um 21:48 Uhr
@PaoloBonzini: Ja, guter Punkt. Eigentlich ist das sogar noch besser, da es den Punkt verstärkt, dass die Verschiebungsoperationen in Form von Werten definiert sind, möglicherweise undefiniert sind, wenn das Ergebnis nicht darstellbar ist, und dass Spekulationen über die zugrunde liegende Darstellung nicht helfen.
– Kerrek SB
1. Januar 2016 um 21:56 Uhr
@KerrekSB: Die Sache ist, dass jeder tatsächlich eine Linksverschiebung braucht, um je nach Fall sowohl als Werte als auch als Repräsentation dargestellt zu werden. Und die Verwendung von Ganzzahlen ohne Vorzeichen kann beispielsweise andere Probleme verursachen x &= -1u << 20 wird höchstwahrscheinlich falsch sein, wenn x ist 64-bit und int ist 32-Bit. Aus diesem Grund verspricht GCC, signierte Verschiebungen niemals als undefiniert oder gar nicht spezifiziert zu behandeln.
– Paolo Bonzini
7. Januar 2016 um 15:10 Uhr
Rick
Obwohl die akzeptierte Antwort darauf hinweist, dass Endianess ein Konzept aus der Erinnerungsansicht ist. Aber ich glaube nicht, dass das die Frage direkt beantwortet.
Einige Antworten sagen mir das bitweise Operationen hängen nicht von Endianness ab, und der Prozessor kann die Bytes auf andere Weise darstellen. Wie auch immer, es geht darum, dass Endianess abstrahiert wird.
Aber wenn wir zum Beispiel einige bitweise Berechnungen auf dem Papier durchführen, müssen Sie dann nicht erst die Endianität angeben? Meistens wählen wir implizit eine Endianess.
Angenommen, wir haben eine Codezeile wie diese
0x1F & 0xEF
Wie würden Sie das Ergebnis von Hand auf einem Papier berechnen?
MSB 0001 1111 LSB
1110 1111
result: 0000 1111
Hier verwenden wir also ein Big-Endian-Format, um die Berechnung durchzuführen. Sie können auch Little Endian verwenden, um zu berechnen und das gleiche Ergebnis zu erhalten.
Übrigens, wenn wir Zahlen in Code schreiben, denke ich, dass es wie ein Big-Endian-Format ist. 123456 oder 0x1Fdie wichtigsten Zahlen beginnen von links.
Nochmals, sobald wir ein binäres Format eines Werts auf das Papier schreiben, haben wir meiner Meinung nach bereits eine Endianess gewählt und sehen den Wert so, wie wir ihn aus dem Gedächtnis sehen.
Also zurück zur Frage, ein Schichtbetrieb << sollte gedacht werden als Verschiebung von LSB (niederwertigstes Byte) nach MSB (höchstwertiges Byte).
Dann wie für das Beispiel in der Frage:
numb=1025
Little-Endian
LSB 00000001 00000100 00000000 00000000 MSB
So << 10 wäre 10bit Umschalten von LSB auf MSB.
Vergleich u << 10 Operationen für das Little-Endian-Format Schritt für Schritt:
MSB LSB
00000000 00000000 00000100 00000001 numb(1025)
00000000 00010000 00000100 00000000 << 10
LSB MSB
00000000 00000100 00010000 00000000 numb(1025) << 10, and put in a Little Endian Format
LSB MSB
00000001 00000100 00000000 00000000 numb(1205) in Little Endian format
00000010 00001000 00000000 00000000 << 1
00000100 00010000 00000000 00000000 << 2
00001000 00100000 00000000 00000000 << 3
00010000 01000000 00000000 00000000 << 4
00100000 10000000 00000000 00000000 << 5
01000000 00000000 00000001 00000000 << 6
10000000 00000000 00000010 00000000 << 7
00000000 00000001 00000100 00000000 << 8
00000000 00000010 00001000 00000000 << 9
00000000 00000100 00010000 00000000 << 10 (check this final result!)
Wow! Ich bekomme das erwartete Ergebnis wie im OP beschrieben!
Die Probleme, dass das OP nicht das erwartete Ergebnis erzielt hat, sind:
Es scheint, dass er nicht von LSB auf MSB umgeschaltet hat.
Wenn Sie Bits im Little-Endian-Format verschieben, sollten Sie Folgendes erkennen (Gott sei Dank ist mir das klar):
LSB 10000000 00000000 MSB << 1 ist LSB 00000000 00000001 MSB, nicht LSB 01000000 00000000 MSB
Denn für jeden Einzelnen 8bitswir schreiben es eigentlich in a MSB 00000000 LSB Big-Endian-Format.
Es ist also wie
LSB[ (MSB 10000000 LSB) (MSB 00000000 LSB) ]MSB
Um zusammenzufassen:
Obwohl gesagt wird, dass bitweise Operationen abstrahiert werden, blablablabla…, wenn wir bitweise Operationen von Hand berechnen, müssen wir immer noch wissen, welche Endianess wir verwenden, wenn wir das Binärformat auf das Papier schreiben. Außerdem müssen wir sicherstellen, dass alle Operatoren die gleiche Endianess verwenden.
Der OP hat nicht das erwartete Ergebnis erzielt, weil er die Schaltung falsch gemacht hat.
Welcher Schiebebefehl die höherwertigen Bits zuerst herausschiebt, wird als Linksverschiebung betrachtet. Welche Verschiebungsanweisung die niederwertigen Bits zuerst herausschiebt, wird als Verschiebung nach rechts betrachtet. In diesem Sinne ist das Verhalten von >> und << zum unsigned Zahlen hängen nicht von Endianness ab.
Computer schreiben Zahlen nicht so auf wie wir. Der Wert verschiebt sich einfach. Wenn Sie darauf bestehen, es Byte für Byte zu betrachten (auch wenn der Computer es nicht so macht), könnten Sie sagen, dass auf einer Little-Endian-Maschine das erste Byte nach links verschoben wird und die überschüssigen Bits in das zweite Byte gehen. usw.
(Übrigens macht Little-Endian mehr Sinn, wenn Sie die Bytes vertikal statt horizontal schreiben, mit höheren Adressen oben. So werden Memory Map-Diagramme üblicherweise gezeichnet.)
14252700cookie-checkHängt die Bitverschiebung von der Endianness ab?yes