8.5 Bit-Operatoren
 
Mit Hilfe von Bit-Operatoren kann direkt auf die binäre Darstellung der Zahlen zurückgegriffen werden.
Zuerst eine kurze Übersicht, welche Bit-Operatoren es gibt:
Tabelle 8.5
Übersicht der bitweisen Operatoren
Bit-Operator
|
Bedeutung
|
&, &=
|
Bitweise AND-Verknüpfung
|
|, |=
|
Bitweise OR-Verknüpfung
|
^, ^=
|
Bitweise XOR
|
~
|
Bitweises Komplement
|
>>, >>=
|
Rechtsverschiebung
|
<<, <<=
|
Linksverschiebung
|
Wie schon bei den arithmetischen Operatoren steht Ihnen auch bei den bitweisen Operatoren die erweiterte Zuweisungsschreibweise zur Verfügung.
Hinweis Es ist nicht zulässig, als Operanden float bzw. double zu verwenden. Die Operanden müssen bei der Verwendung von Bit-Operatoren immer ein ganzzahliger Datentyp sein.
|
8.5.1 Bitweises UND
 
Steht der &-Operator zwischen zwei Operanden, so handelt es sich um den bitweisen UND-Operator. Dieser ist leicht mit dem unären Adressoperator (siehe scanf()) zu verwechseln.
Der Operator wird hauptsächlich dafür verwendet, einzelne Bits gezielt zu löschen. Folgendes Programmbeispiel soll dies demonstrieren:
/* and.c */
#include <stdio.h>
int main(void) {
int x=55;
printf("x=%d\n",x);
x= x&7;
printf("x=%d\n",x); /* x=7 */
return 0;
}
Nach der Ausführung des Programms werden Sie sich fragen, warum die Verknüpfung mit dem UND-Operator zum Ergebnis 7 führt. Sehen Sie sich dies wieder in der Bitdarstellung an (unter Verwendung der ersten 8 Bits):
 Hier klicken, um das Bild zu Vergrößern
Abbildung 8.3
Verwendung des bitweisen UND-Operators
Dabei gelten per Definition folgende Regeln für den bitweisen UND-Operator:
Tabelle 8.6
Regeln einer bitweisen UND-Verknüpfung
BitA
|
BitB
|
BitA&BitB
|
0
|
0
|
0
|
0
|
1
|
0
|
1
|
0
|
0
|
1
|
1
|
1
|
Mit dem bitweisen UND-Operator lässt sich sehr gut testen, ob eine Zahl gerade oder ungerade ist. Es muss nur Bit 0 (bzw. das 1. Bit) daraufhin überprüft werden, ob es gesetzt (ungerade, also = 1) oder nicht gesetzt (gerade, also = 0) ist. Folgendes Beispiel demonstriert dies:
/* gerade.c */
#include <stdio.h>
int main(void) {
int x;
printf("Bitte geben Sie eine Zahl ein: ");
scanf("%d",&x);
if(x&1) // Ist das erste Bit gesetzt?
printf("Eine ungerade Zahl\n");
else // Nein, es ist nicht gesetzt
printf("Eine gerade Zahl\n");
return 0;
}
8.5.2 Bitweises ODER
 
Mit dem bitweisen ODER-Operator können Sie gezielt zusätzliche Bits setzen. Verwendet wird dieser wie schon zuvor der bitweise UND-Operator:
char x = 1;
x = x|126; // x=127
Auch hierzu die Bitdarstellung:
 Hier klicken, um das Bild zu Vergrößern
Abbildung 8.4
Verwendung des bitweisen ODER-Operators
Für den ODER-Operator gilt folgende Verknüpfungstabelle:
Tabelle 8.7
Regeln einer bitweisen ODER-Verknüpfung
BitA
|
BitB
|
(BitA|BitB)
|
0
|
0
|
0
|
0
|
1
|
1
|
1
|
0
|
1
|
1
|
1
|
1
|
8.5.3 Bitweise XOR
 
Dieser exklusive ODER-Operator liefert nur dann eine 1 zurück, wenn beide Bits unterschiedlich sind. Er ist sehr gut geeignet, um Bits umzuschalten. Alle gesetzten Bits werden gelöscht und alle gelöschten gesetzt. Beispielsweise:
char x=20;
x = x^55; // x=35
In binärer Darstellung ergibt sich aus dieser Operation folgendes Bild:
 Hier klicken, um das Bild zu Vergrößern
Abbildung 8.5
Verwendung des exklusiven ODER-Operators
Für XOR-Verknüpfungen gilt folgende Verknüpfungstabelle:
Tabelle 8.8
Regeln einer bitweisen XOR-Verknüpfung
BitA
|
BitB
|
BitA^BitB
|
0
|
0
|
0
|
0
|
1
|
1
|
1
|
0
|
1
|
1
|
1
|
0
|
8.5.4 Bitweises Komplement
 
Der NOT-Operator (~) wirkt sich auf Zahlen so aus, dass er jedes einzelne Bit invertiert. Bei vorzeichenbehafteten Datentypen entspricht das einer Negation mit anschließender Subtraktion von 1:
char x=20;
x=~x; /* x= –21 */
Für den NOT-Operator gilt folgende Verknüpfungstabelle:
Tabelle 8.9
Regeln einer bitweisen NOT-Verknüpfung
BitA
|
~BitA
|
0
|
1
|
1
|
0
|
8.5.5 Linksverschiebung
 
Mit einer Linksverschiebung (<<) werden alle Bits einer Zahl um n Stellen nach links gerückt. Die rechts entstehenden Leerstellen werden mit 0 aufgefüllt.
Achtung Achtung bei Vorzeichen! Ist der Datentyp signed, ändert sich das Vorzeichen, wenn eine 1 in die Bitstelle des Vorzeichens gerückt wird. Falls der linke Operand aber einen negativen Wert hat, so ist das Ergebnis Compiler-spezifisch.
|
Beispiel einer Linksverschiebung:
/* shift_left.c */
#include <stdio.h>
int main(void) {
char x=8;
printf("x=%d\n",x);
x<<=1; // Alle Bits um 1 Stelle nach links
printf("x=%d\n",x);
return 0;
}
Warum aus dem Wert 8 eine 16 wurde, wird aus der folgenden Bitdarstellung ersichtlich:
 Hier klicken, um das Bild zu Vergrößern
Abbildung 8.6
Bitverschiebung nach links
Sie werden es bemerkt haben, hier wurde eine Multiplikation durchgeführt. Auf diese Weise können Zahlen sehr gut potenziert werden. Die Bitstelle um eine Position nach links zu rücken, bedeutet mathematisch eine Multiplikation mit 2. Bei Einrückung um zwei Stellen nach links wird mit 4 multipliziert, bei drei mit 8, bei vier mit 16 usw.
Solche Bitverschiebungen können – abhängig vom System – bis zu 40(!)-mal schneller ablaufen als normale arithmetische Berechnungen im Stil von 4*x.
8.5.6 Rechtsverschiebung
 
Die Rechtsverschiebung mit dem >>-Operator ist das Gegenstück zur Linksverschiebung (<<). Damit können Sie statt einer Multiplikation mit 2 eine Division durch 2 bewirken. Ansonsten gilt das Gleiche wie für die Linksverschiebung.
8.5.7 Rezept für Fortgeschrittene
 
Oft ist eine Funktion wünschenswert, mit der eine Zahl daraufhin getestet wird, ob ein bestimmtes Bit gesetzt ist, oder mit der sich gezielt einzelne Bits setzen oder löschen lassen. Hierzu ein Listing mit entsprechenden Funktionen:
/* playing_bits.c */
#include <stdio.h>
#define BYTE unsigned char
/* Funktion : Bit_Test()
* val : der Wert, den es zu testen gilt
* bit : Bitnummer, die abgefragt wird, ob gesetzt (0–7)
* Rückgabewert : (1)=Bit gesetzt; (0)=Bit nicht gesetzt
*/
int Bit_Test(BYTE val, BYTE bit) {
BYTE test_val = 0x01; /* dezimal 1 / binär 0000 0001 */
/* Bit an entsprechende Pos. schieben */
test_val = (test_val << bit);
/* 0=Bit nicht gesetzt; 1=Bit gesetzt */
if ((val & test_val) == 0)
return 0; /* Nicht gesetzt */
else
return 1; /* gesetzt */
}
/* Funktion : Bit_Set()
* val : Wert, bei dem Bit gesetzt werden soll
* bit : Bitnummer, die gesetzt werden soll (0–7)
* Rückgabewert : keiner
*/
void Bit_Set(BYTE *val, BYTE bit) {
BYTE test_val = 0x01; /* dezimal 1 / binär 0000 0001 */
/* Bit an entsprechende Pos. schieben */
test_val = (test_val << bit);
*val = (*val | test_val); /* Bit an Pos bit setzen */
}
/* Funktion : Bit_Clear()
* val : Wert, bei dem Bit gelöscht werden soll
* bit : Bitnummer, die gelöscht werden soll (0–7)
* Rückgabewert : keiner
*/
void Bit_Clear(BYTE *val, BYTE bit) {
BYTE test_val = 0x01; /* dezimal 1 / binär 0000 0001 */
/* Bit an entsprechende Pos. schieben */
test_val = (test_val << bit);
*val = (*val & (~test_val)); /* Bit an Pos bit löschen*/
}
int main(void) {
BYTE wert = 0;
/* Test, ob Bit 0 gesetzt */
printf("%s\n",Bit_Test(wert, 0)?"gesetzt":"nicht gesetzt");
Bit_Set(&wert, 0); /* Bit 0 setzen */
/* Wieder testen, ob Bit 0 gesetzt */
printf("%s\n",Bit_Test(wert, 0)?"gesetzt":"nicht gesetzt");
Bit_Clear(&wert, 0); /* Bit 0 wieder löschen */
/* Wieder testen ob Bit 0 gesetzt */
printf("%s\n",Bit_Test(wert, 0)?"gesetzt":"nicht gesetzt");
return 0;
}
Die Funktionen können natürlich den eigenen Bedürfnissen entsprechend angepasst werden und dienen nur als Anregung für weitere Spielereien mit Bits und Bytes.
|