Neben Zahlen und Zeichen lassen sich auch Bitmuster und Einzelbits als Daten verarbeiten.

Mit logischen Schaltungen z.B. in einer Arithmetisch-Logischen Einheit (ALU), lassen sich die logischen Maschinenbefehle NICHT, UND, ODER und EODER (exclusives ODER) zur parallelen Verknüpfung von Bitmustern realisieren.

Serielle Schieberegister verschieben Bitmuster um eine oder mehrere Bitpositionen nach rechts oder links.

Bitmuster werden üblicherweise nicht binär durch 0 und 1, sondern kürzer durch Zusammenfassung von 4 Bitpositionen hexadezimal dargestellt.

Bitoperationen sind in C nur auf die ganzzahligen Datentypen char (8 bit), int (16 bit) und long (32 bit) sowohl in der signed als auch in der unsigned Darstellung anwendbar. Die bevorzugten Datentypen für Bitmustervariablen sind int und unsigned int.

Bitmusterkonstanten werden durch den Vorsatz 0x oder 0X vor einer hexadezimalen Ziffernfolge gekennzeichnet; die hexadezimalen Ziffern können sowohl groß (A, B. C, D, E, F) als auch klein (a, b, c, d, e, f ) geschrieben werden. Führende Nullen können wie bei Zahlen sowohl bei Konstanten als auch bei der Eingabe entfallen. Sie werden aber meist angegeben, da es in der binären Speicherdarstellung kein Nichts (Leer) gibt. In besonderen Fällen kann eine Konstante durch Anhängen der Kennbuchstaben u oder U als unsigned und/oder durch l oder L als long (32 bit) gekennzeichnet werden.

Das folgende Beispiel vereinbart zwei Bitmustervariablen und weist ihnen Anfangswerte zu.


int a = 0x00ff, b = 0XFF00;
Erfolgt die Eingabe von Bitmustern mit der scanf-Formatangabe %i (integer), so ist sowohl eine dezimale als auch eine hexadezimale Darstellung auf der Eingabezeile möglich. Hexadezimalzahlen sind wie Konstanten durch den Vorsatz 0x bzw. 0X zu kennzeichnen.

Das folgende Beispiel dient zur Eingabe des Bitmusters 0101 0101 0101 0101:


int a;
scanf ( "%i", &a);
Eingabezeile: 0x5555 cr                        cr steht für carriage return (Eingabetaste)
Erfolgt die Eingabe von Bitmustern mit der scanf-Formatangabe %x bzw. %X (hexadezimal), so ist nur eine hexadezimale Eingabe möglich, das Vorsetzen von 0x bzw. 0X auf der Eingabezeile kann entfallen. In dem folgenden Beispiel wird das Bitmuster 0x5555 und nicht die Dezimalzahl 5555 eingegeben:

int a;
scanf ("%x", &a);
Eingabezeile: 5555 cr

Die hexadezimale Ausgabe von int-Bitmustern kann mit der printf-Formatangabe %nx (Kleinbuchstaben) bzw. %nX (Großbuchstaben) erfolgen; n ist die Breite des Ausgabefeldes. Das Format %0nx gibt führende Nullen anstelle von führenden Leerzeichen aus; die Formatangaben %#0nx bzw. %#0nX setzen 0x bzw. 0X vor die Hexadezimalziffern.

Das folgende Beispiel gibt das Bitmuster 0000 0000 0101 1010 in verschiedenen Darstellungen aus:


int a = Ox005A;
printf ("%X %4X %04X %#06X", a, a, a, a);
Ausgabezeile:5A   5A 005A 0X005A
Die folgende Tabelle zeigt die verfügbaren bitweisen Operatoren und Schiebeoperatoren. Sie lassen sich nur auf die ganzzahligen Datentypen anwenden. Alle folgenden Beispiele setzen voraus, dass drei int-Bitmustervariablen x, a und b vereinbart wurden:
RangOperatorWirkungBeispiel (int x, a, b;)
2 ~ Einerkomplement ~0x01 ergibt 0xFE
6 << n schiebe um n Bit links 0x01 << 1 ergibt 0x02
6 >> n schiebe um n Bit rechts 0x02 >> 1 ergibt 0x01
9 & bitweises UND 0x01 & 0x03 ergibt 0x01
10 ^ bitweises exclusives ODER (XOR) 0x01 ^ 0x03 ergibt 0x02
11 | bitweises ODER 0x01 | 0x03 ergibt 0x03
15 &= & mit Zuweisung x &= y; wie x = x & y;
15 ^= ^ mit Zuweisung x ^= y; wie x = x ^ y;
15 |= | mit Zuweisung x |= y; wie x = x | y;
15 <<= n << n mit Zuweisung x <<= 1; wie x = x << 1
15 >>= n >> n mit Zuweisung x >>= 1; wie x = x >> 1
Bitweise wirkende Operatoren und Schiebeoperatoren

Der Operator ~ bildet das Einerkomplement durch eine Negation aller Bitpositionen.
Beispiel:


a = 0x005A;         /* 0000 0000 0101 1010 */
x = ~ a;         /* 1111 1111 1010 0101 = 0xFFA5 */

Der Operator & bildet das bitweise Und zweier Bitmuster und dient vorzugsweise zum Ausblenden (Löschen) von Bitpositionen mit einer Maske. Das Ergebnis wird in den Bitpositionen auf 0 gesetzt, in denen die Maske 0 ist, und in den Bitpositionen übernommen, in denen die Maske 1 ist.
Das folgende Beispiel löscht alle Bitpositionen bis auf die letzten vier durch die Maske 0x000F:


a = 0x005A;          /* 0000 0000 0101 1010 */
              /* Maske: 0000 0000 0000 1111 */
x = a & 0x000F;      /* 0000 0000 0000 1010 = 0x000A */

Der Operator | bildet das bitweise Oder zweier Bitmuster und kann zum Setzen von Bitpositionen verwendet werden. Das Ergebnis wird in den Bitpositionen auf 1 gesetzt, in denen eine Maske eine 1 enthält, und dort übernommen, wo die Maske 0 ist.
Das folgende Beispiel setzt die vier rechts stehenden Bitposition auf 1.


a = 0x005A;       /* 0000 0000 0101 1010 */
            /*Maske: 0000 0000 0000 1111 */
x = a | 0x000F;          /* 0000 0000 0101 1111 = 0x005F */

Eine andere Anwendung des bitweisen Oder ist die Zusammensetzung eines Bitmusters aus zwei Anteilen, die vorher durch Und-Masken und Verschieben maskiert und in die richtige Position gebracht wurden. Das folgende Beispiel setzt zwei Bytes zu einem Wort (16 bit) zusammen:


a = 0x5500;          /* 0101 0101 0000 0000 */
b = 0x00AA;          /* 0000 0000 1010 1010 */
x = a | b;          /* 0101 0101 1010 1010 = 0x55AA */

Der Operator ^ bildet das bitweise exklusive Oder (XOR) der beiden Operanden und wird dazu verwendet, ein Bitmuster nur an bestimmten Bitpositionen zu komplementieren (negieren). Eine XOR-Schaltung liefert für den Fall, daß beide Eingänge 1 sind, das Ergebnis 0 (entweder oder, aber nicht beide!). Im Gegensatz zum Operator ~, der alle Bitpositionen komplementiert, wird durch den Operator ^ das Ergebnis nur an den Bitpositionen komplementiert, an denen eine Maske eine 1 enthält, und bleibt dort unverändert, wo ein Maskenbit 0 ist.

Das folgende Beispiel komplementiert nur das rechte Byte eines Wortes:


a = 0x5555;     /* 0101 0101 0101 0101 */
         /* Maske: 0000 0000 1111 1111 */
x = a ^ 0x00FF; /* 0101 0101 1010 1010 = 0x55AA */

Die Symbole & bzw. | werden auch im Zusammenhang mit einer logischen Verknüpfung von Aussagewerten (true, false) in der Form && bzw. || verwendet. In dem folgenden Beispiel wird die Variable abbruch wahr, wenn ende oder fehler den Wert true enthält.


int ende, fehler, abbruch;
abbruch = ende || fehler;
Unglücklicherweise ist auch der Ausdruck "abbruch = ende | fehler" zulässig, jedoch wird dabei eine bitweise Verknüpfung der beiden Operanden durchgeführt. Umgekehrt können auch Bitmustervariablen als Aussagen verknüpft werden, wenn man versehentlich die Symbolzeichen & bzw. | einzeln verwendet.

Das folgende (abschreckende) Beispiel zeigt den Unterschied zwischen den Operatoren && und &:


0x0001 && 0x0010 liefert 0x0001 (true && true = true)
0x0001 & 0x0010 liefert 0x0000 (Als Wahrheitswert ist dies false.)

int i = 0x0001, j = 0x0010;
printf("\n&&: %04x", i && j);  /* Ausgabe:&&: 0001 */
printf("\n &: %04x", i & j);   /* Ausgabe: &: 0000 */

Der Links-Schiebeoperator << verschiebt den links stehenden Operanden um die Anzahl der rechts stehenden Stellen nach links. Die links hinausgeschobenen Bits gehen verloren, die rechts frei werdenden Bitpositionen werden mit 0 aufgefüllt. Die Anzahl der Verschiebungen ist ein ganzzahliger Ausdruck (Konstante, Variable oder Kombination).

Das folgende Beispiel verschiebt ein Bitmuster um 4 Bitpositionen nach links und zieht Nullen nach.


a = 0x1234;    /* 0001 0010 0011 0100 */
x = a << 4;    /* 0010 0011 0100 0000 = 0x2340 */
Der Rechts-Schiebeoperator >> verschiebt den links stehenden Operanden um die Anzahl der rechts stehenden Stellen nach rechts. Die Anzahl der Verschiebungen ist ein ganzzahliger Ausdruck (Konstante, Variable oder Kombination). Die rechts hinausgeschobenen Bits gehen verloren. Die Behandlung der links frei werdenden Bitpositionen hängt vom Datentyp des Operanden ab. Bei allen vorzeichenlosen (unsigned) Datentypen wird jede links frei werdende Bitposition mit einer 0 aufgefüllt (logisches Schieben). Das folgende Beispiel verschiebt einen unsigned Operanden um 4 Bitpositionen nach rechts und zieht Nullen nach.

unsigned int x, u;
u = 0x1234;    /* 0001 0010 0011 0100 */
x = u >> 4;    /* 0000 0001 0010 0011 = 0x0123 */
Bei allen vorzeichenbehafteten (signed) Datentypen wird das Vorzeichenbit (MSB) in die frei werdenden Bitposition kopiert. Weil dadurch das Vorzeichen erhalten bleibt, bezeichnet man dies auch als arithmetisches Schieben. Ist das links stehende Bit eine 1, so werden Einsen nachgezogen; ist es eine 0, so werden Nullen nachgezogen.