Forum: Compiler & IDEs Bitfeld-Feld vergleichen, das kleiner als uint8_t ist


von Lukas (Gast)


Lesenswert?

Hi,
ich bekomme in einem 16bit Status Register eines Sensors einige Werte, 
die wenige bits lang sind und möchte sie mit sprintf als Zahl ausgeben 
lassen.

Ich habe mir laut AVR GCC Tutorial ein Bitfeld gebaut. Zuweisen von 
Werten geht ja, aber auslesen?
1
struct {
2
unsigned advanced1:9;
3
unsigned resolution:3;
4
unsigned advanced2:4;
5
} ADVANCED_USER_REG;


gibt's sowas wie
1
uint8_t intRes = (uint8_t) ADVANCED_USER_REG->resolution;

aber natürlich funktionierend, um die Zahl später sinnvoll verwenden zu 
können?
Danke

von Karl H. (kbuchegg)


Lesenswert?

Lukas schrieb:

> gibt's sowas wie
>
>
1
> uint8_t intRes = (uint8_t) ADVANCED_USER_REG->resolution;
2
>
>

Ja, klar geht das.
Jedes C-Buch hilft dir da weiter.

(Du solltest dir eine Daumenregel zu eigen machen: "Ohne Not wird nicht 
gecastet. Niemals". Speziell hier, wenn dir der falsch angewendete Cast 
einen Strich durch die Rechnung macht.)

von Lukas (Gast)


Lesenswert?

Danke.

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

intRes ist kein sinnvoller Name.  Der Name suggeriert den Typ "int",
es ist aber "uint8_t", also insbesondere ein vorzeichenloser Typ.

Lass den halbherzigen Versuch der ungarischen Notation einfach weg:
1
uint8_t Res = ADVANCED_USER_REG->resolution;

Weil wir gerade bei Konventionen sind: BEZEICHNER_IN_GROSSBUCHSTABEN
benutzt man landläufig vorrangig für Makros (um darauf hinzweisen,
dass sich hinter dem Makro diverse Schweinereien verstecken können),
zuweilen auch für die Aufzählungselemente eines enums. Typnamen
schreibt man in kleinbuchstaben oder CamelCase.

von Lukas (Gast)


Lesenswert?

1
>uint8_t Res = ADVANCED_USER_REG->resolution;

macht mir einen compiler error (main.c|122|Fehler: ungültiger 
Argumenttyp von »->« (haben »unsigned int«)|), das habe ich schon 
versucht. es sollte doch prinzipiell kein problem sein, eine 3bit 
unsigned in eine 8bit unsigned variable zu speichern um sie mit sprintf 
ausgeben zu können oder hab ich da einen denkfehler?

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Lukas schrieb:
>
1
>uint8_t Res = ADVANCED_USER_REG->resolution;
>
> macht mir einen compiler error (main.c|122|Fehler: ungültiger
> Argumenttyp von »->« (haben »unsigned int«)|),

Klar, ich habe ja auch nur blind deinen falschen Code übernommen.

Richtig wäre:
1
>uint8_t Res = ADVANCED_USER_REG.resolution;

Aber das sagte ja die Fehlermeldung eigentlich recht gut. ;-)

> es sollte doch prinzipiell kein problem sein, eine 3bit
> unsigned in eine 8bit unsigned variable zu speichern um sie mit sprintf
> ausgeben zu können

Dafür musst du sie auch gar nicht erst in eine extra Variable
speichern.  Vorsicht ist jedoch geboten, da die variable Argument-
liste eines sprintf() eine implizite Konvertierung nach `int'
vornimmt bei der Wertübergabe.  Ich würde dann schreiben:
1
sprintf(buf, "%u", (unsigned)ADVANCED_USER_REG.resolution);

um ganz sicher zu gehen, dass nicht versehentlich ein
vorzeichenbehafteter Datentyp ins Spiel kommt.

von Lukas (Gast)


Lesenswert?

das gibt mir dann
1
main.c|122|Fehler: Anfrage nach Element »resolution« in etwas, was keine Struktur oder Variante ist|

von Rolf Magnus (Gast)


Lesenswert?

Dann ist dein GCC kaputt oder der echte Code sieht doch anders aus. Bei 
mir läßt sich das, in ein Minimalprogramm verpackt, ohne Fehler durch 
den Compiler bringen.

von Helfer (Gast)


Lesenswert?

Funktionieren die Bitfelder in der struct? Ich meine, ein
1
__attribute__ ((packed))

sei da zwingend nötig, um die Bits zusammen zu fassen. Sonst legt der 
Compiler 3 ausreichend grosse unsigned Variablen an. Wenn ich dich 
richtig verstehe, möchtest du das struct über einen uint16_t legen, um 
Bitfelder bequem auszulesen.

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Helfer schrieb
> Ich meine, ein
> _attribute_ ((packed))
>
> sei da zwingend nötig, um die Bits zusammen zu fassen.

Was genau bringt dich zu dieser deiner Meinung?

Es ist genau der Sinn von bit-fields, dass man damit Bits innerhalb
eines größeren Blocks aneinander reihen kann, und das wird auch im
C-Standard formuliert.  Da der AVR außerdem keinerlei memory
alignment benötigt, folgen die einzelnen bit-fields immer direkt
aufeinander.

von Lukas (Gast)


Lesenswert?

sorry, mein fehler, ich hab irgendwo vorher im code mit einer falschen 
zuweisung die originale struct mit einem uint16_t überschrieben. Danke 
trotzdem.

von Helfer (Gast)


Lesenswert?

Jörg Wunsch schrieb

> Was genau bringt dich zu dieser deiner Meinung?

Im GCC Manual heisst es zu diesem Attribut:

/The packed attribute specifies that a variable or structure field 
should have the smallest possible alignment—one byte for a variable, and 
one bit for a field, unless you specify a larger value with the aligned 
attribute./

"one bit for a field" liess mich darauf schliessen, dass es nötig ist, 
den Compiler explizit so anzuweisen. Bisher habe ich das Attribut 
eingesetzt, um grössere structs wie Datei-Header sauber abzubilden (auf 
x86), und die Erfahrungen dort auch auf Bitfelder bezogen. Man lernt nie 
aus... :) Danke.

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Ja, für structs trifft das zu, für bitfields jedoch nicht, und für
den AVR ohnehin nicht.  -fpack-struct ist ein NOP im AVR-GCC.

von Jemand (Gast)


Lesenswert?

Jörg Wunsch schrieb
> Es ist genau der Sinn von bit-fields, dass man damit Bits innerhalb
> eines größeren Blocks aneinander reihen kann, und das wird auch im
> C-Standard formuliert.

Der Sinn von Bitfields ist, mehrere kleine Variablen, die nicht zwingend 
ein Vielfaches von sizeof(char) groß sein müssen, so anlegen zu können, 
daß nicht jede für sich ein ganzzahliges Vielfaches eines Bytes belegt. 
Insbesondere sind sie eigentlich nicht dazu gedacht, die verschiedenen 
Teile eines Hardware-Registers abzubilden.

> Da der AVR außerdem keinerlei memory alignment benötigt, folgen die einzelnen
> bit-fields immer direkt aufeinander.

Das Alignment in Bitfields ist nur bedingt mit dem normalen Alignment zu 
vergleichen. Denn auch die Hardware des AVR hat im Sinne von Bitfields 
Alignment-Anforderungen, nämich Byte-Alignment. Da könnte (und dürfte) 
ein Compiler durchaus auf die Idee kommen, ein 8-Bit-Element so 
auszurichten, daß es genau auf einem Byte zu liegen kommt, statt es über 
zwei Bytes zu verteilen und dann durch entsprechenden Code wieder 
zusammenzustückeln. Ob GCC sowas macht, wirst du besser wissen als ich, 
aber er dürfte es zumindest. Im Unterschied zu normalen structs is bei 
Bitfeldern nicht einmal die Reihenfolge der Elemente im Speicher 
vorgegeben. Der Compiler könnte diese also auch zugunsten einfacheren 
Codes auch beliebig umsortieren.

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Jemand schrieb:
> Da könnte (und dürfte)
> ein Compiler durchaus auf die Idee kommen, ein 8-Bit-Element so
> auszurichten, daß es genau auf einem Byte zu liegen kommt, statt es über
> zwei Bytes zu verteilen und dann durch entsprechenden Code wieder
> zusammenzustückeln.

Richtig, aber dieses Problem besteht hier nicht.  Das erste Bitfeld
ist 9 Bits groß und muss damit zwingend ein zweites Byte belegen.
Die nachfolgenden beiden Bitfelder passen hernach jedoch auf jeden
Fall komplett in das zweite Byte hinein, damit gibt es keinerlei
Grund, für diese noch ein drittes Byte "anzureißen", und der
C-Standard schreibt (obwohl er sonst in Bezug auf bit-fields eher
vage und "implementation-defined" agiert) diese Vorgehensweise de
facto auch noch fest:
1
   ... If enough space remains, a bit-field that immediately follows another bit-field in a
2
   structure shall be packed into adjacent bits of the same unit.  ...

von dasdsad (Gast)


Lesenswert?

Jörg Wunsch schrieb:
1
>    ... If enough space remains, a bit-field that immediately follows
2
> another bit-field in a
3
>    structure shall be packed into adjacent bits of the same unit.  ...

Ohne dass ich den Standard jetzt gelesen hätte, aber "shall" klingt für 
mich eher nach Empfehlung als nach striktem Requirement ("must"), oder? 
Ist das überhaupt so strikt im Standard festgelegt was shall/must/can 
etc. zu bedeuten haben?

von Karl H. (kbuchegg)


Lesenswert?

dasdsad schrieb:
> Jörg Wunsch schrieb:
>
1
>>    ... If enough space remains, a bit-field that immediately follows
2
>> another bit-field in a
3
>>    structure shall be packed into adjacent bits of the same unit.  ...
4
>
>
> Ohne dass ich den Standard jetzt gelesen hätte, aber "shall" klingt für
> mich eher nach Empfehlung als nach striktem Requirement ("must"), oder?
> Ist das überhaupt so strikt im Standard festgelegt was shall/must/can
> etc. zu bedeuten haben?

Ja ist es.

'Shall' bedeutet im C-Standard: Ist absolut einzuhalten.

Das ist wie in der Bibel.
You shall not kill
bedeutet nicht, dass es einem freigestellt ist.

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Karl Heinz Buchegger schrieb:
> 'Shall' bedeutet im C-Standard: Ist absolut einzuhalten.

Nicht nur dort, auch in anderen Standards oder vergleichbaren
Texten, beispielsweise in den RFCs, auf denen das Internet basiert.

von Rolf Magnus (Gast)


Lesenswert?

"Shall" heißt auch "soll" und nicht "sollte".

Karl Heinz Buchegger schrieb:
> 'Shall' bedeutet im C-Standard: Ist absolut einzuhalten.

Das ist dort übrigens auch explizit defniert:

************************************************************************ 
**********
In this International Standard, ‘‘shall’’ is to be interpreted as a 
requirement on an
implementation or on a program; conversely, ‘‘shall not’’ is to be 
interpreted as a
prohibition."
************************************************************************ 
**********

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.