Shift right >>

Der Shift-Right-Operator verschiebt die Bits einer Integer-Zahl um eine gegebene Anzahl nach rechts und füllt die übrigen Bits mit 0 oder bei negativen Zahlen mit 1 auf. Die zu verändernde Zahl steht links des Operators, die Anzahl an zu verschiebender Bit-Stellen steht rechts des Operators.













01001001100101100000001011010010
00100100110010110000000101101001
00000010010011001011000000010110
10110110011010011111110100101110
11111101101100110100111111101001
#include <stdio.h>

void printbinary(int x){
  char str[33]; str[32] = '\0';
  int i = 32;
  while(i){i--; str[i] = (x & 1) + '0'; x>>=1;}
  printf("%s\n", str);
}

int main(){
  int x = 1234567890;
  int y = -1234567890;
  printbinary(x);
  printbinary(x >> 1);
  printbinary(x >> 5);
  printbinary(y);
  printbinary(y >> 5);
  return 0;
}

Siehe auch Shift left <<, Zuweisung >>=

In C++ wird der Shift-Right-Operator zudem oft mit der Eingabe von einem Stream in Zusammenhang gebracht. Siehe dazu die Kommentare bei der Operatoren-Überladung weiter unten.

Details

Der Shift-Right-Operator erwartet zwei Operanden als rvalues und wird von links nach rechts abgearbeitet. Der Rückgabewert ist ein rvalue, der stets ein Integer-Typ ist.

Der Shift-Right-Operator ist nur für Integer-Werte zulässig. Unter C++ ist zusätzlich auch die Anwendung des Operators auf boolsche Werte erlaubt, welche jedoch vor Anwendung des Operators in einen int umgewandelt werden.

Durch das Verschieben der Bits nach rechts werden die übrigbleibenden Stellen am linken Ende mit 0 aufgefüllt. Dies entspricht einem logischen Bitshift in Assembler. Handelt es sich bei dem Typ des ersten Operanden jedoch um einen signed-Typ, so wird das Sign-Bit (höchstwertiges Bit) kopiert. Dadurch bleiben negative Zahlen negativ, was einem arithmetischen Bitshift in Assembler entspricht. Der Shift-Right-Operator wird oftmals mittels SHR abgekürzt.





01001001100101100000001011010010
00000010010011001011000000010110
11101110011010110010100000000000
00000111011100110101100101000000
01001001100101100000001011010010
00000010010011001011000000010110
10110110011010011111110100101110
11111101101100110100111111101001
  unsigned  int x = 1234567890;
  unsigned  int y = 4000000000;
  signed    int z = 1234567890;
  signed    int w = -1234567890;
  printbinary(x);
  printbinary(x >> 5);
  printbinary(y);
  printbinary(y >> 5);
  printbinary(z);
  printbinary(z >> 5);
  printbinary(w);
  printbinary(w >> 5);

Ist die Anzahl zu verschiebender Bits negativ oder grösser als die Länge des verwendeten integer-Typs in Bits, so ist das Resultat nicht spezifiziert. Je nach Compiler können andere Resultate entstehen. In GCC beispielsweise wird die Anzahl zu verschiebender Bits als unsigned-Zahl aufgefasst und modulo der Registerbreite in Bits gerechnet, allerdings gibt der Compiler eine Warnung aus.

Die Operatoren << und >> werden hauptsächlich für low-level Programmierung verwendet, wie beispielsweise in der Systemprogrammierung. Da sie einzelne Bits verändern, wird der Umgang mit diesen Operatoren auch häufig als Bit-fiddling (Bit-Schwindeleien, auch zu verstehen als Bit-Gebastel, oder auf gut Schweizerdeutsch: Umegfätterle mit Bittli) bezeichnet. In der alltäglichen Programmierung finden diese beiden Operatoren heutzutags kaum mehr Verwendung.

Eine heute ab und zu noch anzutreffende Verwendung des Shift-Right-Operators ist die Division einer Zahl mit einer Potenz von 2. Durch die Verschiebung mit 0, 1, 2, 3, ... Bits wird der erste Operand mit 1, 2, 4, 8, ... dividiert. In früheren Zeiten war dies die bevorzugte Art, Zahlen mit einer Potenz von 2 zu dividieren, da ein Bitshift vom Prozessor schneller berechnet werden konnte als eine Division. In heutigen Prozessoren spielt dies keine Rolle mehr.

336
168
84
42
  printf("%d\n", 336 >> 0);
  printf("%d\n", 336 >> 1);
  printf("%d\n", 336 >> 2);
  printf("%d\n", 336 >> 3);

Überladen des Operators

Der Shift-Right-Operator hat grundsätzlich die semantische Bedeutung einer bitweisen Verschiebung nach rechts. Es sei jedoch angemerkt, dass der Shift-Right-Operator mit dieser Semantik äusserst selten überladen wird. Eine sehr bekannte Überladung jedoch ist die Verwendung des Shift-Right-Operators für die Eingabe von einen Stream.

Die Stream-Klassen in der Standardbibliothek <iostream> definieren Operatoren-Überladungen des Shift-Right-Operators, sodass dieser Operator verwendet werden kann, als würde der zweite Operand die Eingabe aus den Stream erhalten, welcher als erster Operand geschrieben wird. In C++ kann somit eine Eingabe mittels folgendem Code erzeugt werden:






Enter a number: 
                12345
The number was 12345
#include <iostream>
using namespace std;

int main(){
  int a;
  printf("Enter a number: ", a);
  cin >> a;
  printf("The number was %i\n", a);
  return 0;
}

Für weiterführende Erklärungen über die Ein- und Ausgabe von und in Streams wird hier auf eine Dokumentation der <iostream>-Bibliothek verwiesen.

Die Prototypen für das Überladen des Shift-Right-Operators sind die folgenden (Einschränkungen und Erläuterungen siehe Überladen von Operatoren):

inside class


outside class
Type operator >>(Type);
Type operator >>(Type) const;

Type operator >>(Type, Type);

Im folgenden Beispiel wird eine Klasse für einen zweidimensionalen Vektor präsentiert. Die Überladung des Shift-Right-Operators liest den Vektor von dem angegebenen Stream. Man beachte dabei, dass hierfür eine Überladung ausserhalb der Klasse verwendet werden muss. Zudem ist es üblich, bei einer solchen Überladung den Stream als lvalue zurückzugeben, wodurch möglich wird, dass mehrere Eingaben hintereinandergereiht werden können. In diesem Beispiel wird ein File eingelesen.

test.txt contents:
10 20
30 40
100 200
300 400

















10.000000, 20.000000
30.000000, 40.000000

100.000000, 200.000000
300.000000, 400.000000
#include <cstdio>
#include <fstream>
using namespace std;

class Vector2{
public:
  float a[2];
  void print(){printf("%f, %f\n", a[0], a[1]);}
};

istream& operator >>(istream& stream, Vector2& v){
  stream >> v.a[0];
  stream >> v.a[1];
  return stream;
}

int main(){
  Vector2 v1;
  Vector2 v2;
  ifstream file("test.txt");
  file >> v1;
  file >> v2;
  v1.print();
  v2.print();
  file >> v1 >> v2;
  v1.print();
  v2.print();
  return 0;
}