C++ Kurs

Bit- und Schiebeoperationen

Die Themen:

Einleitung
Bitoperationen
Schiebeoperationen
Kurzschreibweisen
Beispiel und Übung

Einleitung

Bisher wurden Operationen nur auf Bytes oder einem Vielfachen  davon (char, short, int, long Variablen bzw. Konstanten) ausgeführt. C++ bietet jedoch auch die Möglichkeit, einzelne Bits von Ganzzahlen mithilfe von Bitoperationen zu beeinflussen.

Da Bitoperationen nur auf Ganzzahlen zulässig sind, können mit ihnen (unter der Annahme, dass char gleich 8 Bits enthält) sizeof(char)*8, sizeof(short)*8, sizeof(int)*8 oder sizeof(long)*8 Bits gleichzeitig beeinflusst werden, abhängig davon, ob die Bitoperation auf einen char, short, int oder long Datentyp angewandt wird. Bis auf den Bitoperator 'rechts schieben' arbeiten alle Bitoperatoren vorzeichenunabhängig, d.h. sie wirken auf signed und unsigned Daten gleich.

Bitoperationen sind binäre Operationen, d.h. die Ganzzahl wird hier als eine Kombination von 0 und 1 Bits ausgewertet.

Bevor es gleich mit den Operationen los geht, nochmals zur Wiederholung die binäre Darstellung von Ganzzahlen anhand einer unsigned char Variablen (Annahme: char gleich 8 Bits).

Wert 10 => hex: 0x0A => binär: 0000 1010
Wert: 240 => hex: 0xF0 => binär: 1111 0000
Wert: 131 => hex: 0x83 => binär: 1000 0011

 

Bitoperationen

Um einzelne Bits einer Ganzzahl zu beeinflussen, stehen die folgenden Bitoperationen zur Verfügung:

UND-Operation

Zwei Operanden werden durch den Operator & UND-verknüpft.

ergebnis = operand1 & operand2;

Die UND-Verknüpfung liefert als Ergebnis nur an den Stellen ein 1-Bit, an denen beiden Operanden ein 1-Bit besitzen.

Beispiel:

operand1   operand2   ergebnis
0x26 (0010 0110) & 0x23 (0010 0011) => 0x22 (0010 0010)
0x45 (0100 0101) & 0x0F (0000 1111) => 0x05 (0000 0101)

ODER-Operation

Zwei Operanden werden durch den Operator | ODER-verknüpft.

ergebnis = operand1 | operand2;

Die ODER-Verknüpfung liefert als Ergebnis an den Stellen ein 1-Bit, an denen mindestens einer der Operanden ein 1-Bit besitzt.

Beispiel:

operand1   operand2   ergebnis
0x26 (0010 0110) | 0x23 (0010 0011) => 0x27 (0010 0111)
0x45 (0100 0101) | 0x0F (0000 1111) => 0x4F (0100 1111)

EXKLUSIV-ODER Operation

Zwei Operanden werden durch den Operator ^ EXKLUSIV-ODER-verknüpft.

ergebnis = operand1 ^ operand2;

Die EXKLUSIV-ODER Verknüpfung liefert als Ergebnis an den Stellen ein 1-Bit, an denen beide Operanden unterschiedliche Bits besitzen

Sollten Sie Schwierigkeiten haben das Symbol ^ für den Exklusiv-Oder Operator zu finden: es befindet sich auf der deutschen Tastatur neben der 1-Taste. Um das Symbol ^ zu erhalten, drücken Sie zuerst die Taste ^ und dann die Leertaste!

Beispiel:

operand1   operand2   ergebnis
0x26 (0010 0110) ^ 0x23 (0010 0011) => 0x05 (0000 0101)
0x45 (0100 0101) ^ 0x0F (0000 1111) => 0x4A (0100 1010)

NEGATION-Operation (1er Komplement)

Für die Invertierung aller Bits eines Operanden wird der Operator ~ verwendet.

ergebnis = ~operand;

Das Ergebnis enthält an den Stellen ein 1-Bit, an denen der Operand ein 0-Bit besitzt und umgekehrt. Man bezeichnet diese Operation auch als Bildung des 1er-Komplements.

Beispiel:

operand   ergebnis
~0x26 (0010 0110 => 0xD9 (1101 1001)
~0x45 (0100 0101) => 0xBA (1011 1010)

Schiebeoperationen

Außer den Bitoperationen stellt C++ auch noch Operatoren zur Verfügung, um die Bits einer Ganzzahl um eine bestimmte Anzahl von Positionen nach links oder rechts zu schieben.

SHIFT-LEFT Operation

Die Bits eines Operanden können mithilfe des Operators << um eine definierte Anzahl von Bits nach links geschoben werden.

ergebnis = operand << bitzahl;

Die rechts frei werdenden Bits werden mit 0 aufgefüllt und Überläufe werden verworfen.

Beispiel:

operand1   bitzahl   ergebnis
0x26 (0010 0110) << 2 => 0x98 (1001 1000)
0x45 (0100 0101) << 4 => 0x50 (0101 0000)

SHIFT-RIGHT Operation

Die Bits eines Operanden können mithilfe des Operators >> um eine definierte Anzahl von Bits nach rechts geschoben werden.

ergebnis = operand >> bitzahl;

Ist die Ganzzahl vorzeichenlos (unsigned), werden die links frei werdenden Bits mit 0 aufgefüllt. Bei positiven vorzeichenbehafteten Zahlen werden die frei werdenden Bits ebenfalls mit 0 aufgefüllt.

Bei negativen Zahlen ist das Verhalten lt. ANSI C++ undefiniert. In der Regel werden die freiwerdenden Bits aber mit dem Vorzeichenbit (höchstwertiges Bit, bei negativen Zahlen gleich '1') aufgefüllt.

Beispiel:

operand1   bitzahl   ergebnis
0x26 (0010 0110) >> 2 => 0x09 (0000 1001)
0x45 (0100 0101) >> 4 => 0x04 (0000 0100)

Kurzschreibweisen

Genauso wie bei den Grundrechenoperationen, stehen auch für die Bit- und Schiebeoperationen entsprechende Kurzschreibweisen zur Verfügung, die in der nachfolgenden Tabelle aufgeführt sind.

x &= y    x = x & y
x |= y    x = x | y 
x ^= y    x = x ^ y
x <<= y    x = x << y
x >>= y    x = x >> y 

Beispiel und Übung

Beispiel:

Einer unsigned short Variable nVar wird der Hex-Wert 0xAA55 zugewiesen. Von dieser Variable wird dann einmal das High-Byte und einmal das Low-Byte ausgegeben.

Hinweis: Eine unsigned short Variable besteht hier aus 2 Bytes. Diese Bytes werden durch entsprechendes Schieben und Ausmaskieren (logische Verundung mit einer Bitkombination) extrahiert.

Danach werden durch Schiebeoperationen die 2er Potenzen im Bereich 20 bis 23 gebildet.

Zum Schluss wird die Zahl 244 mittels einer Schiebeoperation durch 8 dividiert.

High-Byte von 0xaa55: 0xaa
Low-Byte von 0xaa55: 0x55
2 hoch 0: 1
2 hoch 1: 2
2 hoch 2: 4
2 hoch 3: 8
244/8: 30


// Beispiel zu Bitoperationen

// Zuerst Dateien iostream und iomanip einbinden
#include <iostream>
#include <iomanip>

using std::cout;
using std::endl;

// Variable für Zerlegung definieren
unsigned short var = 0xAA55;

// main() Funktion
int main ()
{
   // Ausgabe auf hex umstellen mit Angabe der Zahlenbasis
   cout << std::hex << std::showbase;
   // High-Byte der Variablen ausgeben
   cout << "High-Byte von " << var << ": " << (var>>8) << endl;
   // Low-Byte der Variablen ausgeben
   cout << "Low-Byte von " << var << ": " << (var&0xFF) << endl;
   // Ausgabe wieder auf dezimal zurückstellen
   cout << std::dec;

   // 2er Potenzen ausgeben
   cout << "2 hoch 0: " << (1<<0) << endl;
   cout << "2 hoch 1: " << (1<<1) << endl;
   cout << "2 hoch 2: " << (1<<2) << endl;
   cout << "2 hoch 3: " << (1<<3) << endl;

   // Zum Schluss eine Division durch 8
   cout << "244/8: " << (244>>3) << endl;
}

Übung:

Es ist eine short Variable shortVar und eine char Variable charVar zu definieren. Die short Variable ist mit 10 und die char Variable mit dem Hex-Wert 0x55 zu initialisieren.

Anschließend ist die char Variable charVar in binärer Darstellung (nur 0 und 1) auszugeben. Verwenden Sie dazu nur Bitoperationen.

Von der short Variablen shortVar ist zunächst das 1er-Komplement zu bilden und auszugeben. Addieren Sie zu dem so erhaltenen Ergebnis eins hinzu und geben das Ergebnis erneut aus. Welche Zahl erhalten Sie?

0x55 nach binär: 01010101
Das 1er Komplement von 10: ???
Und eins dazuaddiert ergibt: ???

Lösung ansehen!