Hallo zusammen,
angenommen ich habe ein 8 Bit Array mit zwei Werten und eine 16 Bit
Variable auf einem 16-Bit Microcontroller.
1
uint8Array[2];
2
uint16Var;
Wenn ich jetzt Array[0] mit Array[1] zu einem 16 Bit Wert zusammensetzen
möchte, kann ich das auf folgende Art machen?
1
Var=(Array[0]+(Array[1]<<0x08));
oder brauche ich folgenden cast:
1
Var=(Array[0]+(uint16)Array[1]<<0x08);
Wenn ich den 8 Bit Wert um 8 Stellen schiebe, dann bekomme ich einen
Overflow oder weiß der Compiler an dieser Stelle, was ich machen möchte
und schiebt den 8 Bit Wert auf eine 16 Bit Variable?
Der Compiler "weiß" nicht, was du willst. :)
Aber: es gibt integer promotion rules. Die besagen, dass alle
Operanden erstmal mindestens auf die Größe eines "int" gebracht werden,
und der wiederum hat mindestens 16 bit.
Insofern klappt das hier.
Was anderes wäre es, wenn es um 2 x 16 => 32 bit handeln würde. Dort
hängt es davon ab, ob ein "int" in der Plattform 16 oder 32 bit breit
ist.
ETK99899 schrieb:> Hallo zusammen,>> angenommen ich habe ein 8 Bit Array mit zwei Werten und eine 16 Bit> Variable auf einem 16-Bit Microcontroller.
Das ist zweitrangig. Entscheidend ist, welche Breite der Datentyp int
hat. Der ist selbst auf einem 8-Bit AVR 16 Bit.
> uint8 Array[2];> uint16 Var;>> Wenn ich jetzt Array[0] mit Array[1] zu einem 16 Bit Wert zusammensetzen> möchte, kann ich das auf folgende Art machen?> Var = (Array[0] + (Array[1] << 0x08));
Ja.
> oder brauche ich folgenden cast:> Var = (Array[0] + (uint16)Array[1] << 0x08);
Nein, wenn gleich das die wasserdichte Variante ist, falls bei irgend
einem speziellen Compiler int weniger als 16 Bit hat (was AFAIK laut
C-Standard nicht zulässig ist, es gibt sie aber).
> Wenn ich den 8 Bit Wert um 8 Stellen schiebe, dann bekomme ich einen> Overflow
Ja.
oder weiß der Compiler an dieser Stelle, was ich machen möchte
> und schiebt den 8 Bit Wert auf eine 16 Bit Variable?
Ja, Stichwort integer Promotion.
Franko P. schrieb:> Andere Möglichkeit ist das union
Diese ist allerdings nicht "endianess agnostic", d.h. das exakte
Verhalten ist von der konkreten Implementierung abhängig.
Die Bitschieberei ist dagegen immer eindeutig.
Hallo Jörg
habe das union in dem Anwendingsfall schon öfter verwendet um die bytes
aus dem short rauszuholen (oder umgekehrt), und hatte noch nie ein
Problem. Was könnte da als Problem oder Fehler passieren?
Gruß
gerhard
Franko P. schrieb:> Was könnte da als Problem oder Fehler passieren?
Dass du beim Übergang auf eine andere Architektur (oder sogar auf einen
anderen Compiler) dann halt das "falsche" der beiden Bytes zuerst
bekommst.
Die Anordnung der Bytes ist "implementation-defined".
Zugegeben, die meisten heutigen Architekturen sind little endian (oder
werden so betrieben), aber PowerPC beispielsweise ist ein aktuell nach
wie vor relevantes Gegenbeispiel (UltraSPARC auch, findet man aber wohl
höchstens noch auf großkalibrigen Servern, seit Oracle Sun geschluckt
hat).
Franko P. schrieb:> Was könnte da als Problem oder Fehler passieren? G
In der Praxis wohl zu erst die falsche Endianes.
Theoretisch darf er da machen, was er will.
Jörg W. schrieb:> A. S. schrieb:>> Theoretisch darf er da machen, was er will.>> Er muss es aber dokumentieren: es ist "implementation-defined", nicht> "undefined".
Er darf ganz sicher nicht machen was er will. Es ist definiert, was der
Compiler an dieser Stelle machen muss. Das Ergebnis ist
implementation-defined, weil die Repräsentation der Objekte
implementation-defined ist. Das einzige was der Compiler an dieser
Stelle dokumentieren muss ist Repräsentation von integer-Objekten.
ETK99899 schrieb:> uint8 Array[2];> uint16 Var;>> Wenn ich jetzt Array[0] mit Array[1] zu einem 16 Bit Wert zusammensetzen> möchte, kann ich das auf folgende Art machen?> Var = (Array[0] + (Array[1] << 0x08));
Leute, ist es nicht problematisch? Array[1] ist ja uint8_t und 0x08
eine int-Zahl.
Und das
1
Array[1]<<0x08)
wird als int berechnet. Das kann z.B so ein Bitmuster ergeben:
0b1111111100000000 = 65280 (dezimal).
Aber INT16_MAX=32767.
D.h. die Zahl passt da nicht rein. Und es wird jetzt zu dieser
(falschen) Zahl noch was dazu addiert:
1
(Array[0]+(Array[1]<<0x08)
Und das soll auch mit int-Werten berechnet werden.
shifty shiff schrieb:> D.h. die Zahl passt da nicht rein. Und es wird jetzt zu dieser> (falschen) Zahl noch was dazu addiert:
Stimmt, das ist problematisch.
Man sollte statt der Addition ein bitweises ODER nehmen:
1
Var=Array[0]|(Array[1]<<0x08);
Da dieses keinen Überlauf erzeugen kann, ist die sich ergebende
Operation immer definiert.
Jörg W. schrieb:> Da dieses keinen Überlauf erzeugen kann, ist die sich ergebende> Operation immer definiert.
Schieben und Addieren kann auch keinen Überlauf erzeugen, denn die
hereingeschobenen Bits sind IMMMER Null. Damit ist Addition und
ODER-Verknüfung identisch.