C-Basic: Bitmanipulation setzen, löschen und wechseln von Bits in C/C++
Dieser Beitrag gibt einen Überblick über einige Tipps und praktische Konzepte zur Bit-Manipulation und zeigt, wie sie in der C / embedded-C Programmierung eingesetzt werden kann. Insbesonderer für Lese- und Schreibzugriffe auf Register bei der Programmierung von Mikrocontrollern ist die Bearbeitung einzelner Bits ein Grundwerkzeug.
Die Grundlage
In einem Binärsystem existieren nur die Werte 0 und 1 und das n-te Bit (einschließlich 0) entspricht einem Wert von
Definitionen:
- Ein gelöschtes oder “low, false” Bit entspricht einer 0
- Ein gesetztes oder “high, true” Bit entspricht eine 1
- Das ganz linke Bit hat den höchsten Wert und wird daher als das höchstwertigste Bit englisch (Most-Significant Bit, MSB) bezeichnet.
- Das ganz rechte Bit hat den niedrigsten Wert und wird daher als niederwertigstes Bit englisch (Least-Significant Bit, LSB) bezeichnet.
Addition
Für die Addition gelten die folgenden Regeln:
- 0 + 0 ergibt: 0
- 0 + 1 ergibt: 1
- 1 + 1 ergibt: 0 mit einer übertragenen 1 auf die nächsthöhere Stelle
Die Addition von () und () ergibt somit ()
1011 + 1010 _____ 10101
Subtraktion
Für die Subtraktion gelten folgende Regeln:
- 0 – 0 ergibt: 0
- 1 – 0 ergibt: 1
- 1 – 1 ergibt: 0
- 10 – 1 ergibt: 01
Die Subtraktion von () und () ergibt somit ()
1011 - 1010 _____ 0001
Multiplikation
Bei der Multiplikation muss wie folgt bitweise vorgegangen werden. Jedes Bit aus A mit einem Wert wird mit jedem Bit aus B und dessen Wert “multiplizieren”, indem B um die Position des Wertes von B verschoben wird. Im Anschluss an die Verschiebung werden die beiden addiert. Um beispielsweise A = () und B = () zu multiplizieren, wird B um jedes Bit in A verschoben. Für dieses Beispiel ergeben sich somit zwei Verschiebungen von B, welche dann addiert werden:
- Verschiebung um 1 nach links für von A ergibt B1 mit
- Verschiebung um 0 nach links für von A ergibt B2 mit
- Addition von B1 und B2 ergibt ()
Die Multiplikation von () und () ergibt somit ()
1011 x 1010 _____ 1101110
Komplement
Die Komplement-Bildung auch als Drehen, Negieren oder einfaches Umkehren bezeichnet, ändert alle 1er auf 0er und umgekehrt. Dieser Vorgang wird in C mit dem Operator ~ durchgeführt. Beispiele für die Komplementbildung:
- ~1 ergibt: 0
- ~0 ergibt: 1
- ~01101011 ergibt: 10010100
Der NICHT-Operator ! entspricht nicht dem Kompliment da dieser nicht bitweise sondern den gesamten Wert manipuliert!
Beispiele:
- !01101011 ergibt: 00000000
- !00000000 ergibt: 00000001
ODER-Verknüpfung (OR)
Die ODER-Verknüpfung ist die erste reine Binärverknüpfung (man kann dies nicht mit Dezimalzahlen vollziehen). In C wird sie mit dem Operator | durchgeführt. Um zwei Binärwerte zu “ODERn”, gelten folgende Regeln:
- 0 | 0 ergibt: 0
- 0 | 1 ergibt: 1
- 1 | 1 ergibt: 1
1011 | 1010 _____ 1011
UND-Verknüpfung (AND)
Die UND-Verknüpfung wird in C mit dem Operator & durchgeführt. Um zwei Binärwerte zu “UNDn”, gelten folgende Regeln:
- 0 | 0 ergibt: 0
- 0 | 1 ergibt: 0
- 1 | 1 ergibt: 1
1011 & 1010 _____ 1010
Exklusiv-ODER-Verknüpfung (XOR)
Die Exklusiv-ODER-Verknüpfung wird in C mit dem Operator ^ durchgeführt. Um zwei Binärwerte zu “XORn”, gelten folgende Regeln:
- 0 | 0 ergibt: 0
- 0 | 1 ergibt: 1
- 1 | 1 ergibt: 0
1011 ^ 1010 _____ 0001
Shifting (Bits verschieben)
Durch Verschieben, nach links mit << und nach rechts mit >>, wird ein Binärwert um eine bestimmte Anzahl von Bits nach links oder rechts verschoben. Die durch die Verschiebung freiwerdenden Stellen werden mit 0 gefüllt.
Beispiele:
- 01101011 << 2 ergibt: 10101100
- 01101011 >> 4 ergibt: 00000110
Bitmanipulation
In den folgenden Abschnitten wird gezeigt, wie man in einer Bitfolge gezielt einzelne Bits setzt, löscht oder umkehrt.
Setzen eines bestimmten Bits (set)
Das setzen von Bits beruht auf der Kombination aus einem Shift und einer ODER-Verknüpfung oder einer Bitmaske und einer ODER-Verknüpfung.
Um das te Bit in der Variable zu setzen (von 0 an gezählt) wird folgende Formel verwendet:
- A |= (1 << n)
Beispiele:
- 0100 |= (1 << 0) ergibt: 0100 | 0001 ergibt: 01001
- 0100 |= (1 << 2) ergibt: 0100 | 0100 ergibt: 0100 (keine Veränderung)
Für das Setzen von Bits bei der Mikrocontroller-programmierung mit C bietet es sich an, das folgende Macro zu verwenden:
#define SET_BIT(byte, bit) ((byte) |= (1UL << (bit)))
Alternativ lässt sich ein Bit auch direkt über eine Maske setzen:
- A |= Bit-Maske
Beispiel:
- 1000 |= 0010 ergibt: 1010
- 1000 |= 1000 ergibt: 1000 (keine Veränderung)
Löschen eines bestimmten Bits (clear)
Das löschen eines Bits kann durch die Kombination aus einem Shift, dem Komplement und der UND-Verknüpfung realisiert werden. Auch hier besteht die Möglichkeit anstelle des Verschiebens eine Bit-Maske zu nutzen.
Um das te Bit in der Variable zu löschen (von 0 an gezählt) wird folgende Formel verwendet:
- A &= ~(1 << n)
Beispiele:
- 0101 &= ~(1 << 2) ergibt: 0101 & 1011 ergibt: 0001
- 0010 &= ~(1 << 1) ergibt: 0010 & 1101 ergibt: 0000
- 0010 &= ~(1 << 0) ergibt: 0010 & 1110 ergibt: 0010(keine Veränderung)
Ebenso ist das Setzen von Bits bei der Mikrocontroller-programmierung mit C über ein Macro möglich:
#define CLEAR_BIT(byte,bit) ((byte) &= ~(1UL << (bit)))
Alternativ lässt sich ein Bit auch direkt über eine Maske löschen:
- A &= ~(Bit-Maske)
Beispiel:
- 0101 &= ~0100 ergibt: 0001
- 1000 &= ~1000 ergibt: 0000
Wechseln eines bestimmten Bits (toggle)
Das Wechseln eines Bits geschieht durch die Kombination der Shift-Funktion und der Exklusiv-ODER-Verknüpfung. Dabei wird das entsprechende Bit von 0 auf 1 oder von 1 auf 0 gesetzt.
Um den Zustand des te Bits in der Variable zu wechseln (von 0 an gezählt) wird folgende Formel verwendet:
- A ^= (1 << n)
Beispiele:
- 0100 ^= (1 << 2) ergibt: 0100 ^ 0100 ergibt: 0000
- 0101 ^= (1 << 1) ergibt: 0101 ^ 0010 ergibt: 0111
- 1101 ^= (1 << 0) ergibt: 1101 ^ 0001 ergibt: 1100
Ebenso ist das Wechseln von Bits bei der Mikrocontroller-programmierung mit C über ein Macro möglich:
#define TOGGLE_BIT(byte,bit) ((byte) ^= (1UL << (bit)))
Alternativ lässt sich ein Bit auch direkt über eine Maske wechseln:
- A ^= (Bit-Maske)
Beispiel:
- 0101 ^= 0100 ergibt: 0001
- 1000 ^= 0100 ergibt: 1100
Aktualisieren eines bestimmten Bits (update)
Um ein spezifisches Bit zu aktualisieren, muss dies zuerst gelöscht werden und dann mit dem zu setzenden Wert ODER-Verknüpft werden.
Um den Zustand des te Bits in der Variable zu aktualisieren (von 0 an gezählt) wird folgende Formel verwendet:
- A &= ~(1 << n)
- A |= (Wert << n)
Überprüfung eines bestimmten Bits (check)
Die Überprüfung eines speziellen Bits geschieht durch einen Shift und eine UND-Verknüpfung. Wenn das Bit gesetzt ist erhält man eine 1 anderenfalls eine 0.
Um den Zustand des te Bits in der Variable zu prüfen (von 0 an gezählt) wird folgende Formel verwendet:
- A &= (1 << n)
Beispiel:
- 0101 &= 0100 ergibt: 0100 ergibt: true
- 0101 &= 1000 ergibt: 0000 ergibt: false
Ebenso ist das Überprüfen von Bits bei der Mikrocontroller-programmierung mit C über ein Macro möglich:
#define IS_SET(byte,bit) (((byte) & (1UL << (bit))) >> (bit))
Vielen Dank für den schönen Artikel. Er erklärt den Sachverhalt wirklich gut.
Glaube aber bei “Setzen eines bestimmten Bits(set)” ist ein kleiner Typ drin.
0100 |= (1 << 0) ergibt: 0100 | 0001 ergibt: 01001 // das Ergebnis hat eine Null zu viel un müsste 0101 sein