BIT - Verständniss

CodeFatal

Erfahrenes Mitglied
Moin moin zusammen,

ich habe in einem älteren Projekt folgenden Code gefunden.

Code:
struct bits
{
unsigned abc:1;
unsigned def:1;
};

#define CLOE              CKS_bit.no4


typedef struct
  {
    unsigned char no0:1;
    unsigned char no1:1;
    unsigned char no2:1;
    unsigned char no3:1;
    unsigned char no4:1;
    unsigned char no5:1;
    unsigned char no6:1;
    unsigned char no7:1;
  } __BITS8;

Das ganze stammt aus einem Programm für einen Chip. also kein Microsoft Compiler oder so...
ich vermute mal das da versucht wurde ne Bit addressierung zu realisieren... bisher ist mir aber nur untergekommen, das man Bit mit den Bitoperatoren ansprechen kann aber nicht im Speicher anlegen kann.
Schafft man dies mit dem Doppelpunkt dann doch oder ist das ne Compiler spezifische Sache :confused:

Für Schaffung von Algemeinverständniss wär ich dankbar

Gruss Michael
 
Das hast Du richtig erkannt, mit Hilfe dieser Doppelpunkt Notation innerhalb eines structs kann man ein sogenanntes Bitfeld definieren. Das ist Standard C, wird im K&R mit folgendem Beispiel beschrieben:
Code:
struct {
    unsigned int is_keyword : 1;
    unsigned int is_extern  : 1;
    unsigned int is_static  : 1;
} flags;
Jetzt kann man die Bits ganz einfach setzen mittels
Code:
flags.is_extern = flags.is_static = 1;
Jetzt kommt jedoch das große ABER. Denn leider sind solche Bitfelder implementierungsabhängig und -- noch viel schlimmer -- architekturabhängig. Das heißt »ob ein Bit-Feld eine Wortgrenze überschreiten kann, hängt von der Implementierung ab« und Du musst genau wissen, ob Du eine little-endian oder big-endian Maschine hast, bzw. ob Dein Programm nur auf einer Prozessorarchitektur laufen soll (was bei einem Chipdesign ja dann wieder okay ist). Daher sind Programme mit Bitfeldern nicht portabel! Im K&R steht übrigens, dass Bitfelder nur als int vereinbart werden dürfen. Außerdem gibt es keine Vektoren von Bitfeldern und Bitfelder haben keine Adressen (also gilt auch kein Adressoperator &).

Im Linux Kernel wirst Du beispielsweise dieses Konstrukt nie sehen. Das Dilemma ist, dass man als kleinste definierte Datenstruktur ein unsigned char mit 8 Bit hat. Deshalb wird bei Linux immer __u8 oder u8 genutzt, um ein Byte zu adressieren:
Code:
#define __u8    unsigned char
Innerhalb dieses Bytes kannst Du dann mit Shiften, UNDen und ODERn alle möglichen Kombinationen durchspielen. Man erstellt sich dann Makros, die eine Funktion simulieren. Beispielsweise:
Code:
#define __set_r(b, v)           (b | ((v & 0x01) << 7))
Für die architekturunabhängigkeit greift man ganz am Ende auf Konvertierungen zurück (host-to-byte o.ä.).

Bitfummeleien sind nicht schön und durch Makros natürlich auch nicht typsicher, aber erfüllen ihren Zweck. Nützlich ist eine gute Dokumentation oder wenigstens aussagekräftige Namen der Makros, damit man auch nach einiger Zeit noch weiß, was da geschieht.

HTH,
Martin
 
Bei Microcontrollern wird sowas schon mal angewandt. Z.B. bei Übertragungaprotokollen kann man so recht einfach Telegrammheader zusammensetzen.
Aber: Aufpassen auf den Controllertyp (siehe rohrbold). Die Zahl nach dem Doppelpunkt sagt aus, wieviele Bits die Variable belegt. Die einzelnem Variablen werden dann hintereinander in den übergeordneten Datentyp gelegt. In Deinem Beispiel belegt jede Variable 1 Bit, es können aber auch größere Zahlen angegeben werden.
 
Danke für eure Antworten.
Hab mir so was schon gedacht.. Komm eigentlich aus der 2k/ XP Welt und da war mir die Addressenlosigkeit von Bits bekannt... hatte die da immer mit SHIFTen UNDen und ODERn berabeitet... Bei 2k/ XP ist mir der Doppelpunkt daher auch nie begegnet.
Der Code stammt wie gesagt aus einem Programm für einen speziellen Chip und sollte nun portiert werden... Da ist das Problem mit Compiler Wechsel und der von euch angesprochenen nicht Portabilität dann natürlich aufgetaucht...

Danke nochmals

Gruss Michael
 
Zurück