gesucht "beste" Möglichkeit in c Bitfilds zu definieren

Gast #6375765
Lesenswert?

Hallo,

dieses ist eine sicher nicht allgemeingültig zu beantwortende Frage, und 
ich denke hier hat jeder seine ganz eigenen Ansichten zu. Trotzdem frage 
ich nach euren Meinungen und der Begründung warum es für euch die beste 
Möglichkeit darstellt.

Also zunächst ein bisschen Vorgabe
1
typedef struct testStruct{
2
uint16_t  VarA;
3
uint16_t  VarB;
4
? 8BitField 
5
}test_TypeDefSt

es geht darum wie am besten dieses 8 Bit Bitfild implementiert wird.

Variante 1:
1
#define FLAG1 ((uint8_t)0x01U
2
#define FLAG2 ((uint8_t)0x02U
3
#define FLAG3 ((uint8_t)0x04U
4
#define FLAG4 ((uint8_t)0x08U
5
#define FLAG5 ((uint8_t)0x10U
6
#define FLAG6 ((uint8_t)0x20U
7
#define FLAG7 ((uint8_t)0x40U
8
#define FLAG8 ((uint8_t)0x80U
9

10
typedef struct testStruct{
11
uint16_t  VarA;
12
uint16_t  VarB;
13
uint8_t BitField;
14
}test_TypeDefSt

zugriff dann über Veroderung


Variante 2: wie Variante 1 nur mit einem typedef enum für die Flags

Variante 3:
1
typedef struct FlagsStruct{
2
uint8_t flag1 :1;
3
uint8_t flag2 :1;
4
uint8_t flag3 :1;
5
uint8_t flag4 :1;
6
uint8_t flag5 :1;
7
uint8_t flag6 :1;
8
uint8_t flag7 :1;
9
uint8_t flag8 :1;
10
}flags_TypeDefSt
11

12
typedef struct testStruct{
13
uint16_t  VarA;
14
uint16_t  VarB;
15
flags_TypeDefSt BitField;
16
}test_TypeDefSt

zugriff mittels var.BitFild.flagX

ist sichergestellt das der compiler hier nur 8 bit belegt?

gibt es eine einfache Möglichkeit dieses Bielefeld wieder in einem 
uint8_t (char) abzulegen und zu senden? ist hier ein cast gefahrlos 
möglich?

Variante 4:
eure Ideen

Variante 1 ist sicher der Klassiker, allerdings sieht man beim Debuggen 
nicht welche Flags gesetzt sind, was bei größeren Strukturen dann schon 
unübersichtlich werden kann.
#6375774
Lesenswert?

Try this:
1
typedef struct FlagsStruct {
2
      uint8_t flag1 : 1;
3
      uint8_t flag2 : 1;
4
      uint8_t flag3 : 1;
5
      uint8_t flag4 : 1;
6
      uint8_t flag5 : 1;
7
      uint8_t flag6 : 1;
8
      uint8_t flag7 : 1;
9
      uint8_t flag8 : 1;
10
    }flags_TypeDefSt;
11

12
    union bla {
13
      uint8_t u8;
14
      flags_TypeDefSt flags;
15
    } blub;
16

17
    blub.u8 = 0;
18
    blub.flags.flag1 = 1;
19
    blub.flags.flag8 = 1;
Persönliche Seite #6375778
Lesenswert?

fragender schrieb:
> ist sichergestellt das der compiler hier nur 8 bit belegt?

Nein.

fragender schrieb:
> gibt es eine einfache Möglichkeit dieses Bielefeld wieder in einem
> uint8_t (char) abzulegen und zu senden?

Nein.

fragender schrieb:
> ist hier ein cast gefahrlos
> möglich?

Nein, denn das Ergebnis ist implementation defined, d.h. es kommt je 
nach Compiler, Plattform, ... etwas anderes heraus.

Wenn du also Bitfelder (und andere Daten) verschicken und wieder 
einlesen möchtest, siehe Serialisierung. Meine µSer-Bibliothek 
ermöglicht u.a. das Senden und Empfangen von Bitfeldern auf 
plattform-unabhängige portable Weise:

https://github.com/Erlkoenig90/uSer

Siehe z.B. in der Doku:
https://erlkoenig90.github.io/uSer-doc/html/tutorial.html#ConWidth

Ben S. schrieb:
> Try this:

Ist in C auch implementation defined, und in C++ ganz verboten.
Gast #6376453
Lesenswert?

@Niklas G.
Vielen Dank werde mir das auf jeden Fall mal ansehen :)


ich hatte mit Absicht das Typwandeln mittels union nicht als Beispiel 
aufgeführt, da so etwas immer zu Problemen führen kann.

mit dem verwenden des uint8_t hatte ich gehofft einen 8 bit Wert 
erzwingen zu können.

Werde mich jetzt erst mal in die µSer einlesen, klingt spannend
Persönliche Seite #6376475
Lesenswert?

Matthias S. schrieb:
> Zumindest der gcc arm-abi und der avrgcc schlucken das.

Es wird aber eben keine portable Zusammensetzung der Bits garantiert. 
Der selbe Bitfield-basierte Code kann mit unterschiedlichen Compilern 
(-Versionen, -Optionen) unterschiedliche Ergebnisse haben. Das ist für 
portablen Code nicht so gut. Daher sind Flags mit bitweisen Operationen 
besser, nur leider unübersichtlich; daher die µSer-Library, welche die 
komfortabel kapselt.

fragender schrieb:
> Werde mich jetzt erst mal in die µSer einlesen, klingt spannend

Viel Erfolg ;-)
#6376983
Lesenswert?

Matthias S. schrieb:
> Niklas G. schrieb:
>> Das ist für
>> portablen Code nicht so gut.
>
> Da kümmere ich mich dann drum, wenn ich es portieren möchte.

Mit der Einstellung kommt dann meistens Code raus, bei dem ein 
Neuschreiben nicht viel mehr Aufwand ist als eine Portierung.
Wenn man von vorne herein etwas mitdenkt, kann man ohne großen 
Meheraufwand einen Großteil des Code gleich so schreiben, dass eine 
Portierung nachher trivial ist.
Gast #6377590
Lesenswert?

Rolf M. schrieb:
> kann man ohne großen Meheraufwand einen Großteil des Code gleich so
> schreiben, dass eine Portierung nachher trivial ist.

In C ist der Aufwand oft riesig, wenn man mit HW oder Telegrammen 
interagiert oder verschiedene int-größen hat. (Wenn nicht, dann, braucht 
man das natürlich nicht).

Mir ist es lieber, der Code ist lesbar und abgesichert, z.B. durch 
CT-Asserts. Man kann die interaktionsfreien Teile ja portabel halten. 
Und beim Rest passt man halt die Header (Strukturen, typedefs) an.
Gast #6377674
Lesenswert?

A. S. schrieb:
> In C ist der Aufwand oft riesig

Selber schuld wenn man C nimmt ;-) In C++ ist es möglich Bibliotheken 
wie o.g. zu implementieren welche das sehr einfach machen. Man kann das 
auch von C aus einbinden wenn man eine Datei per C++ kompilieren kann.

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren