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?
>
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.)
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_tRes=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.
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?
>> 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_tRes=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:
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.
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.
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.
sorry, mein fehler, ich hab irgendwo vorher im code mit einer falschen
zuweisung die originale struct mit einem uint16_t überschrieben. Danke
trotzdem.
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.
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.
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. ...
> ... 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?
>> ... 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.
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.
"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."
************************************************************************
**********