Bitmanipulationen

Bei der Programmierung von Microcontrollern und beim Steuern von elektronischen Schaltungen muss man sehr häufig bestimmte Bits setzen, löschen oder auslesen. Hier finden sich die Grundlagen, wie man das in C machen kann.

Bit(s) testen

if ((variable & bitmaske) == bitmaske)

testet, ob alle in der Bitmaske angegebenen Bits gesetzt sind. Falls man nur prüfen will, ob irgendwelche Bits der Maske gesetzt sind, reicht:

if (variable & bitmaske)

Bit(s) setzen

variable |= bitmaske;

Bedarf wohl keiner weiteren Erklärung

Bit(s) löschen

variable &= ~(bitmaske);

ebenfalls einfache boolsche Algebra, nicht vergessen die Maske zu invertieren.

Bit(s) invertieren

Mittels des XOR-Operators können einzelne oder mehrere Bits invertiert werden:

variable ^= (bitmaske);

Bit(s) schieben

Mit << kann man Bits nach links schieben, z.B. wird mit "1<<4" die 1 um vier Stellen nach links geschoben - ergibt also den Wert 16.

Ebenso kann man mit >> Bits nach rechts schieben.

Hierbei gibt es aber bei grösseren Datentypen eine Stolperfalle: Die "1" wird vom Compiler als Typ "Integer" angesehen. Zum Beispiel beim AVR-GCC ist Integer aber nur 16 Bit, wenn man den shift Operator nun auf eine 32-Bit Variable anwendet, geht das schief. So löst man das dann korrekt:

int32_t reg_32;
uint64_t reg_64;

reg_32 |= ((uint32_t)1 << 23);	/* Setze Bit 23 */
reg_32 |= (1L << 23);		/* kürzere Schreibweise */
reg_64 |= (1LL << 51);		/* Setze Bit 51 */

Zwei Variablen tauschen ohne Hilfsvariable

Wenn man so verzweifelt um Speicher ringt, dass man sich keine Hilfsvariablen mehr erlauben kann, ist meist ohnehin Assembler angesagt.
Da Assembler aber Prozessorspezifisch ist, möchte ich das Prinzip hier in C zeigen. Die verwendete Prozessorarchitektur muss XOR auf die Zielwerte anwenden können, um eine echte Ersparnis zu erhalten (wenn die Werte erst in Register kopiert werden müssen, kann man gleich ein Register als Hilfsvariable nehmen).

void xchng(uint8_t *r0, uint8_t *r1)
{
	*r0 ^= *r1;
	*r1 ^= *r0;
	*r0 ^= *r1;
}