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
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.
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.
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
@ 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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.