Bitfelder

Aus der Mikrocontroller.net Artikelsammlung, mit Beiträgen verschiedener Autoren (siehe Versionsgeschichte)
Wechseln zu: Navigation, Suche

Beim Programmieren von Mikrocontrollern muss auf jedes Byte oder sogar auf jedes Bit geachtet werden. Oft müssen wir in einer Variablen lediglich den Zustand 0 oder 1 speichern. Wenn wir nun zur Speicherung eines einzelnen Wertes den kleinsten bekannten Datentypen, nämlich unsigned char, nehmen, dann verschwenden wir 7 Bits, da ein unsigned char 8 Bits breit ist.

Hier bietet uns die Programmiersprache C ein mächtiges Werkzeug an, mit dessen Hilfe wir 8 Bits in eine einzelne Bytevariable zusammenfassen und (fast) wie 8 einzelne Variablen ansprechen können. Die Rede ist von sogenannten Bitfeldern. Diese werden als Strukturelemente definiert. Sehen wir uns dazu doch am besten gleich ein Beispiel an:

struct {
   unsigned bStatus_1:1; // 1 Bit für bStatus_1
   unsigned bStatus_2:1; // 1 Bit für bStatus_2
   unsigned bNochNBit:1; // Und hier noch mal ein Bit
   unsigned b2Bits:2;    // Dieses Feld ist 2 Bits breit
   // All das hat in einer einzigen Byte-Variable Platz.
   // die 3 verbleibenden Bits bleiben ungenutzt
} x;

Der Zugriff auf ein solches Feld erfolgt nun, wie beim Strukturzugriff bekannt, über den Punkt- oder den Dereferenzierungs-Operator:

x.bStatus_1 = 1;
x.bStatus_2 = 0;
x.b2Bits = 3;

Bitfelder sparen Platz im RAM, zu Lasten von Rechenzeit zum Zerlegen des Bytes in seine einzelnen bits. Besteht also kein triftiger Grund sollten nur Datentypen mit längen die Vielfache von 8bit sind verwendet werden, auch wenn nur ein Bitwert gespeichert werden soll.

Es kann sinnvoll sein, als Basistyp "unsigned char/short" statt "unsigned" zu wählen. Viele Plattformen behandeln ein als "unsigned" deklariertes Bitfeld hinsichtlich Aligment wie ein normales "unsigned". Ein Array aus der oben definierten Struct würde dann pro Element 2 oder 4 Bytes benötigen.

So wird im ARM ABI

struct { unsigned i:1; }

auf 4 Bytes aligned,

struct { unsigned char i:1; }

aber nicht.

Wenn portabler Code geschrieben wird, sollten jedoch nur die Basistypen "_Bool", "signed int" oder "unsigned int" verwendet werden, da nur diese durch den Standard garantiert sind[1]. Ob andere Typen erlaubt sind, hängt vom verwendeten Compiler ab und kann in dessen Handbuch nachgelesen werden.


<references>