Forum: Compiler & IDEs 3 byte variable mit 20 + 4 bit


von Philipp C. (ba4_philipp)


Lesenswert?

Hallo,

ich möchte einen seriellen Datenstrom in eine Variable einlesen. Dazu 
benutze ich bis jetzt ein long int. Die Daten die kommen haben 
allerdings nur 24Bit (3Byte). Ausserdem stellen die ersten 20bit eine 
Kennung da und nur die lezten 4 bit sind eigentliche Daten. Ich habe 
bisher mit struct gearbeitet um zB einzelne Bits in einem Byte 
zusammenzufassen, aber wie geht man nun an das Problem mit 20bit heran?

Wenn man in einer struct
unsigned long int id:20
unsigend char data:4

machen würde, werden dann auch nur 3 Byte belegt oder ist es mit einer 
struct ohnehin die falsche Herangehensweise?

Ich würde am Ende gerne die Variable füllen in dem ich beim Anfang der 
Übertrtagung sage:

var = 0;

Dann die 1 setze mit:

var |= 1L << bitnummer;

und am Ende würde ich dann gerne var.id und var.data einzeln auswerten 
können. Kann mir jmd sagen wie man soetwas am geschicktesten 
implementiert?

Vielen Dank
Gruß Philipp

von G. L. (sprintersb)


Lesenswert?

Di kannst dir eine Union bauen:
1
typedef union
2
{
3
   struct 
4
   {
5
      unsigned long int id:20;
6
      unsigend char data:4;
7
   } val;
8
9
   struct
10
   {
11
      unsigned bit0:1;
12
      unsigned bit1:1;
13
      unsigned bit2:1;
14
      ...
15
   } bits;
16
} data24_t;

und kannst dann drauf zugreifen wie gewünscht:
1
 data24_t data; 
2
 if (data.bits.bit0)
3
    ...
4
 data.val.id   = 0x12345;
5
 data.val.data = 5;

Alternativ kannst du Tipparbeit sparen, indem du die erste struct anonym 
machst (kein ANSI, nur noch GNU-C):
1
typedef union
2
{
3
   struct 
4
   {
5
      unsigned long int id:20;
6
      unsigend char data:4;
7
   };
8
9
   struct
10
   {
11
      ...
12
   } bits;
13
} data24_t;
1
 data24_t data; 
2
 if (data.bits.bit0)
3
    ...
4
 data.id   = 0x12345;
5
 data.data = 5;

Sinnvoll ist eine 24-Bit Struktur/Union allerdings nur dann, wenn du 
Arrays davon verwendest bzw. sehr viele Komposite, die ausser dieser 
Struktur noch andere Daten dahinter enthalten. Dies wird dann 
Speicherplatz sparen.

Was den Code-Verbrauch angeht, ist es uU deutlich günstiger, die 
Struktur/Union auf 32 Bit aufzublasen, auch wenn 8 Bit ungenutzt 
bleiben. Grund ist, daß je nach Compiler (zB GCC) 32-Bit-Objkete in 
Registern gehalten werden können, während das für 24-Bit-Objekte 
(allgemein für Objekte, deren Bytegröße keine 2-Potenz ist) nicht in 
Regs gehalten werden und im Frame leben, was Code und Frame kostet.

von Simon K. (simon) Benutzerseite


Lesenswert?

Deine Variante ist schön schnell, aber auch mit Vorsicht zu genießen, da 
das Ergebnis bei deiner Methode undefiniert ist.

Verlassen würde ich mich erst darauf, wenn du es ausprobiert hast. 
Genormt ist an der Union nur, dass man auf gleichem Wege rauslesen soll, 
wie man auch hereinschreibt. Sonst ist das Ergebnis, wie gesagt, 
undefiniert und damit Compiler, Platform... abhängig.

von Philipp C. (ba4_philipp)


Lesenswert?

Hallo,

im Prinzip brauch ich die bits nicht direkt ansprechen und wenn es eh 
auf 4 Byte aufgeblasen werden sollte (sind nicht viele von den 
Variablen, die benöigt werden) dann könnte man es doch auch so machen 
oder:
1
typedef union
2
{
3
   struct 
4
   {
5
      unsigned long int id:20;
6
      unsigend char data:4;
7
   };
8
      unsigned long int raw;
9
} data24_t;
10
11
data24_t data;

Das würde das long int raw Teil ja mit im gleichen Speicher liegen wie 
die struct und ich könnte mit
1
data24_t data;
2
data.raw = 0;
3
4
data.raw |= 1L << bit;
das ganze Ding auf 0 setzen und dann einzelne bits (also bit) setzen.
Am Ende kann man dann data.id und data.data auslesen oder mache ich da 
einen Denkfehler?

Vielen Dank schonmal
Gruß Philipp

von StinkyWinky (Gast)


Lesenswert?

@ Georg-johann Lay

Die Struktur aus Deinem Vorschlag benötigt aber doch 5 Byte. Wenn Du 
dann noch ein Array von denen anlegst, wird durch das Alignement wohl 
noch ein bisserl mehr daraus. Kommt natürlich auf die 
Zielsystem-Architektur an.

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.