Bei Strukturen in C kann ich ja die Größe von Mitgliedern auf eine
konkrete Anzahl Bits einschränken.
1
struct{
2
unsignedintgenau:1;
3
unsignedintmitjein:2;
4
}antwort;
Wie weise ich jetzt so einem Mitglied der Struktur den Inhalt einer
Variable zu, ohne dass der gcc beim Compilieren schon warnt, dass 8 Bits
nicht in 3 passen (may change value [-Wconversion]) ?
Dass der Wert in der Variable klein genug ist, wird vorher im Programm
schon sicher gestellt.
Ich will auch nicht die Warnungen für problematische Zuweisungen ganz
ausschalten. In anderen Fällen hilft ja ein expliziter Typecast, um dem
Compiler zu sagen : ich weiß, was ich hier tue.
foobar schrieb:> Generell: wenn du nicht wirklich Speichersorgen hast, vermeide> Bitfields.
Nein.
Nutze Bitfelder, wenn sie Sinn machen.
Vermeide sie, wenn nicht.
1. Was nicht funktioniert: Den Wert mit einer entsprechenden Maske zu
verUNDen löst das Problem nicht, die Warnung bleibt.
1
x &= 0b11;
2. Was nicht funktioniert: Dem Compiler mitteilen, das die Wert in den
Grenzen liegt. Aber die Warnung bleibt:
1
if (x > 0b11)
2
__builtin_unreachable();
oder
1
if (x > 0b11)
2
__builtin_unreachable();
3
else
4
s.b = x;
3. Was nicht funktioniert: Cast auf den Typ von s.b mit
"__typeof__(s.b)". Ergibt einen Fehler vom Compiler weil das Argument
von typeof ein Bitfeld ist.
Das Problem mit -Wconversion scheint schon recht alt zu sein:
https://gcc.gnu.org/PR39170
was 2009 gegen v4.3 reportiert wurde; aber v8 und master (v13) zeigen
immer noch das gleiche Verhalten. Und der PR hat Status "assigned",
nicht etwa "resolved" oder "fixed".
Stattdessen wird -Wtraditional-conversion vorgeschlagen, was jedoch
>> -Wtraditional-conversion>> Warn of prototypes causing type conversions different>> from what would happen in the absence of prototype.
ist also was anderes...
struct {
unit8_t
genau : 1,
mitjein : 2,
: 5;
} __attribute__((_packed_)) antwort_t;
antwort_t anwort;
... so gehts bei avr gcc, klar der type kann auch einzeln wiederholt
werden und dann wie bekannt antwort.genau.
du kannst auch auf unit16_t/uint32_t mappen
e.g. dann
#define ANTWORT_FLAG(genau) (*(antwort_t*) &antwort).b
also cast ptr auf type struct
FOp schrieb:> Bei Strukturen in C kann ich ja die Größe von Mitgliedern auf eine> konkrete Anzahl Bits einschränken.
Besser nicht.
Wenn Du so eine verquere Struct brauchst, z.B. für einen IC oder ein
Protokoll, dann schreibe besser eine Funktion, die Dir das erst für die
Ausgabe so hinbastelt bzw. eine Eingabe wieder in einzelne Variablen
aufdröselt.
Das spart dann auch Code und Rechenzeit, wenn der Compiler sich nicht
bei jedem Rechenschritt extra verrenken muß (AND, OR, SHIFT usw).
Danke für die ganzen Antworten.
Was ich in der Tat nicht gesucht habe sind Lösungen, die darauf
vertrauen, wie der Compiler etwas umsetzt, z.B. Typecasts über Zeiger.
Wenn das ganze MISRA konform bleiben muss sind ja schon Unions verpönt,
wenn sie ausnutzen, wie der Compiler die Daten im Speicher anordnet.
Das mit dem & 1 hatte ich auch schon ausprobiert. Es führt beim
arm-none-eabi-gcc (GNU Tools for STM32 10.3-2021.10.20211105-1100)
10.3.1 20210824 (release) wenn er für einen cortex-m4 compiliert dazu,
dass wirklich ein zusätzlicher Assembler Befehl eingebaut wird. Ok,
vermutlich kaum nennenswert im Vergleich zu dem Zusatzaufwand die Bits
zusammen und wieder auseinander zu pfriemeln.
Die Pragmas helfen natürlich auch, wenn man sich sicher ist, warum die
Warnungen kommen. Ich hatte erwartet, dass es da auch was im C-Standard
gibt, um auszudrücken, was der Programmierer will. Für so abgespaced
hatte ich die Vorgehensweise nicht gehalten, dass nicht schon einige vor
mir darauf gestossen wären.
So lange es beim gcc bleibt, sind keine Änderungen an den Pragmas
fällig. Sobald das zum ersten Mal auf einen Compiler portiert werden
soll, der die Pragmas nicht kennt, kommen die & rein.
FOp schrieb:> Danke für die ganzen Antworten.>> Was ich in der Tat nicht gesucht habe sind Lösungen, die darauf> vertrauen, wie der Compiler etwas umsetzt, z.B. Typecasts über Zeiger.
Dann sind Bitfelder aber das falsche, denn die sind abhängig davon, wie
der Compiler sie umsetzt. Gerade deshalb sollte man sie dafür nicht
verwenden.
Rolf M. schrieb:> Dann sind Bitfelder aber das falsche, denn die sind abhängig davon, wie> der Compiler sie umsetzt. Gerade deshalb sollte man sie dafür nicht> verwenden.
Äh nee. Compilerabhängig wird es erst, wenn Du einerseits normal darauf
zugreifst und andererseits wilde Typecasts, gar noch über Pointer
machst, Unions oder andere Tricks verwendest, damit sie sich mit einem
SFR oder einer Variable eines anderen Typs den Speicherplatz teilen, und
dann darauf zugreifst. Wenn Du sie auf dem vorgesehenen Weg befüllst und
wieder ausliest ist alles in Butter. Oder es ist zumindest sehr
schwierig zu scheitern, denn der Compiler weiß ja, was der Compiler tut.
FOp schrieb:> Wenn Du sie auf dem vorgesehenen Weg befüllst und wieder ausliest ist> alles in Butter.
Ah, ok. Ich dachte, du willst die befüllen, um die Daten in irgendwelche
Hardware-Register zu stecken oder irgendein Protokoll umzusetzen. Wenn
du die tatsächlich nur einfach in die Struktur schreibst und später
wieder ausliest, dann ist es natürlich kein Problem. Dann ergibt sich
aber tatsächlich die Frage, ob dein Speicher wirklich so knapp ist, dass
du darauf zurückgreifen musst.