Hallo,
über der seriellen Schnittstelle wird 8bit Datenkette versendet,
die als 10bit Zeichenkette interpretiert werden soll.
aus : abcdefgh ijklmnop qrstuvwx ....
wird: abcdefghij klmnopqrst uvwx....
meine Lösung um ohne bitshifting die Variablen umzuwandeln:
1
typedefstruct{
2
uint16_tb0:10;
3
uint16_tb1:10;
4
uint16_tb2:10;
5
uint16_tb3:10;
6
}uint10b_t;
7
8
typedefunion{
9
uint10b_tdata10;
10
uint8_tdata8[5];
11
}data_u;
12
13
intmain(void)
14
{
15
data_udata;
16
data.data8[0]=255;
17
data.data8[1]=255;
18
data.data10.b0;// enthält 1023
19
data.data10.b1;// enthält 63
20
}
Soweit läuft es auch wie gewollt.
Nachteil ist jedoch dass man die 10bit Variablen nicht in einer
Schleife sondern einzeln bearbeiten muss, da man kein Bit-Array
erstellen kann, und ich deshalb den Umweg mittels struct gehe.
Als ich mich genauer damit befasst habe, habe ich festgestellt,
dass dieser Weg nicht elegant ist, da das alignment vom Compiler
nicht garantiert wird.
Ist das "unleserliche" bit-shifting der einzige Weg, der wirklich
zulässig ist, oder gibt es noch andere Lösungen um sowas zu casten?
p41145 schrieb:> meine Lösung um ohne bitshifting die Variablen umzuwandeln:
Was meinst Du, was der Compiler anstellt, wenn er auf Deine Bitfelder
zugreift?
Ja klar mach der Compiler das im Endeffekt per bitshifting,
nur mit dem Unterschied, dass man den Code besser lesen kann.
Es kann jedoch passieren, dass ein anderer Compiler die 10bits
in einem uint16_t packt und nicht mehr shiftet.
Deshalb mein Posting, vielleicht hat jemand einen anderen Ansatz.
p41145 schrieb:> Es kann jedoch passieren, dass ein anderer Compiler die 10bits> in einem uint16_t packt und nicht mehr shiftet.
Das kann nur passieren, wenn Du Dein Bitfeld nicht als "gepacktes"
Bitfeld deklarierst.
Siehe
Normalerweise gibt es bitfelder nur gepackt in Einheiten des verwendeten
Typs.
Du hast einen 16 bit-typ, dann sollten darin 3 5-bit-felder möglich
sein, aber nur ein 10bit Feld. Zum nächsten sollt 6bit frei bleiben
Ma W. schrieb:> Typumwandlung mit union ist Undefined Behavior.
Nicht seit C99 in C.
> Man darf nicht in ein Union-Feld etwas schreiben und es aus einem> anderen Union-Feld rücklesen.
Doch, darf man. Type-punning per Union ist erlaubt. Im Zusammenhang mit
Bitfeldern ist das Ergebnis dann allerdings implementationsabhängig,
weil nicht spezifiziert ist, wie herum die Bits eingepackt werden.
Wenn man portablen Code haben will, sollte man Bitfelder ausschließlich
zum Laden und Speichern nutzen.
Kaj G. schrieb:> Da wir nicht wissen, ob der TO C oder C++ verwendet, ist die Frage nach> dem "UB or not UB" etwas muessig.
Kurze Antwort: Ich benutze C (gnu99)
Also sehe ich es richtig, es ist nicht zulässig,
funktioniert aber trotzdem Compilerabhängig?
Nop schrieb:> Ma W. schrieb:>> Typumwandlung mit union ist Undefined Behavior.>> Nicht seit C99 in C.
In auch nicht mit gcc. Da steht im Kleingedruckten, dass Type-Punning
per Union explizit unterstützt wird; auch vor C99. gcc verwendet dieses
Feature bei der Implementation der libgcc z.B. für Fixed-Point und
Floating-Point Support.
p41145 schrieb:> Also sehe ich es richtig, es ist nicht zulässig,
Doch, ist es in C99 und später. gnu99 setzt auf C99 nur noch ein paar
Erweiterungen drauf.
Aber es ist nicht portabel, weil nicht festgelegt ist, wie herum der
Compiler die Bitfields implementiert - MSB oben oder unten und Endianess
seien genannt. Deswegen sollte man Bitfields für sowas nicht verwenden,
sondern das mit richtigen Umwandlungen machen.
p41145 schrieb:> Nachteil ist jedoch dass man die 10bit Variablen nicht in einer> Schleife sondern einzeln bearbeiten muss
Und man darf sich auch nicht im Listing anschauen, welch riesen Bohei
der Compiler für Bitfelder veranstalten muß.
Ich würds einfach mit ner Funktion machen, dann geht auch ne Schleife.
Peter D. schrieb:> Ich würds einfach mit ner Funktion machen, dann geht auch ne> Schleife.uint16_t get10bit( uint8_t *p, uint8_t i )> {> return *(uint16_t *)(p+i) >> i*2 & 0x03FF;> }
Bist Du sicher daß der Code das macht was gefordert ist?
Bernd K. schrieb:> Bist Du sicher daß der Code das macht was gefordert ist?
Ich kann zumindest bestätigen, dass es bis zu 5x8bit zu
4x10bit gut funktioniert. Man muss den Pointer alle vier
10bits nochmal um ein byte versetzen dann klappt es auch
für größere Arrays.
@Peter Dannegger:
Die Priorität der Operatoren finde ich nicht trivial,
schwer so zu lesen, aber ein guter Ansatz.
p41145 schrieb:> Die Priorität der Operatoren finde ich nicht trivial,> schwer so zu lesen, aber ein guter Ansatz.
Ich muß zugeben, ich hatte erst ein switch/case erstellt und dann
geschaut, wie sich die 4 Case unterscheiden.