Die Bitverschiebungsoperatoren tun genau das, was ihr Name impliziert. Sie verschieben Bits. Hier ist eine kurze (oder nicht so kurze) Einführung in die verschiedenen Schichtbetreiber.
Die Betreiber
>>
ist der arithmetische (oder vorzeichenbehaftete) Rechtsverschiebungsoperator.
>>>
ist der logische (oder vorzeichenlose) Rechtsschichtoperator.
<<
ist der Linksverschiebungsoperator und erfüllt die Anforderungen sowohl logischer als auch arithmetischer Verschiebungen.
Alle diese Operatoren können auf ganzzahlige Werte angewendet werden ( int
, long
, gegebenenfalls short
und byte
oder char
). In einigen Sprachen wird int
der Operand durch Anwenden der Verschiebungsoperatoren auf einen beliebigen Datentyp, der kleiner als automatisch ist, automatisch geändert int
.
Beachten Sie, dass dies <<<
kein Operator ist, da er redundant wäre.
Beachten Sie auch, dass C und C ++ nicht zwischen den rechten Schichtoperatoren unterscheiden . Sie stellen nur den >>
Operator bereit , und das Rechtsverschiebungsverhalten ist die für signierte Typen definierte Implementierung. Der Rest der Antwort verwendet die C # / Java-Operatoren.
(In allen gängigen C- und C ++ - Implementierungen, einschließlich GCC und Clang / LLVM, sind >>
signierte Typen arithmetisch. Einige Codes setzen dies voraus, dies wird jedoch vom Standard nicht garantiert. Es ist jedoch nicht undefiniert . Der Standard erfordert Implementierungen, um ihn zu definieren So oder so. Linksverschiebungen von negativ vorzeichenbehafteten Zahlen sind jedoch undefiniertes Verhalten (vorzeichenbehafteter Ganzzahlüberlauf). Wenn Sie also keine arithmetische Rechtsverschiebung benötigen, ist es normalerweise eine gute Idee, Ihre Bitverschiebung mit vorzeichenlosen Typen durchzuführen.)
Linksverschiebung (<<)
Ganzzahlen werden im Speicher als eine Reihe von Bits gespeichert. Die als 32-Bit gespeicherte Nummer 6 int
wäre beispielsweise:
00000000 00000000 00000000 00000110
Wenn Sie dieses Bitmuster um eine Position ( 6 << 1
) nach links verschieben, erhalten Sie die Nummer 12:
00000000 00000000 00000000 00001100
Wie Sie sehen können, haben sich die Ziffern um eine Position nach links verschoben, und die letzte Ziffer rechts ist mit einer Null gefüllt. Sie können auch feststellen, dass das Verschieben nach links einer Multiplikation mit Potenzen von 2 6 << 1
entspricht . Dies entspricht also 6 * 2
und 6 << 3
entspricht 6 * 8
. Ein guter optimierender Compiler ersetzt Multiplikationen nach Möglichkeit durch Verschiebungen.
Nicht kreisförmige Verschiebung
Bitte beachten Sie, dass dies keine Kreisverschiebungen sind. Verschieben Sie diesen Wert um eine Position nach links ( 3,758,096,384 << 1
):
11100000 00000000 00000000 00000000
Ergebnisse in 3.221.225.472:
11000000 00000000 00000000 00000000
Die Ziffer, die "vom Ende" verschoben wird, geht verloren. Es wickelt sich nicht herum.
Logische Rechtsverschiebung (>>>)
Eine logische Rechtsverschiebung ist die Umkehrung zur Linksverschiebung. Anstatt Bits nach links zu verschieben, bewegen sie sich einfach nach rechts. Zum Beispiel die Nummer 12 verschieben:
00000000 00000000 00000000 00001100
rechts um eine Position ( 12 >>> 1
) erhalten wir unsere ursprüngliche 6 zurück:
00000000 00000000 00000000 00000110
Wir sehen also, dass eine Verschiebung nach rechts einer Division durch Potenzen von 2 entspricht.
Verlorene Teile sind weg
Eine Verschiebung kann jedoch keine "verlorenen" Bits zurückfordern. Wenn wir zum Beispiel dieses Muster verschieben:
00111000 00000000 00000000 00000110
links 4 Positionen ( 939,524,102 << 4
) erhalten wir 2.147.483.744:
10000000 00000000 00000000 01100000
und dann zurückschalten ( (939,524,102 << 4) >>> 4
) erhalten wir 134.217.734:
00001000 00000000 00000000 00000110
Wir können unseren ursprünglichen Wert nicht zurückerhalten, wenn wir Bits verloren haben.
Arithmetische Rechtsverschiebung (>>)
Die arithmetische Rechtsverschiebung entspricht genau der logischen Rechtsverschiebung, außer dass anstelle des Auffüllens mit Null das höchstwertige Bit aufgefüllt wird. Dies liegt daran, dass das höchstwertige Bit das Vorzeichenbit oder das Bit ist, das positive und negative Zahlen unterscheidet. Durch Auffüllen mit dem höchstwertigen Bit bleibt die arithmetische Rechtsverschiebung vorzeichenerhaltend.
Wenn wir dieses Bitmuster beispielsweise als negative Zahl interpretieren:
10000000 00000000 00000000 01100000
Wir haben die Nummer -2.147.483.552. Wenn wir dies mit der arithmetischen Verschiebung (-2.147.483.552 >> 4) um 4 Positionen nach rechts verschieben, erhalten wir:
11111000 00000000 00000000 00000110
oder die Nummer -134,217,722.
Wir sehen also, dass wir das Vorzeichen unserer negativen Zahlen beibehalten haben, indem wir die arithmetische Rechtsverschiebung anstelle der logischen Rechtsverschiebung verwenden. Und wieder sehen wir, dass wir eine Division durch Potenzen von 2 durchführen.