Forum: Mikrocontroller und Digitale Elektronik Schieben mit oder ohne cast


von ETK99899 (Gast)


Lesenswert?

Hallo zusammen,

angenommen ich habe ein 8 Bit Array mit zwei Werten und eine 16 Bit 
Variable auf einem 16-Bit Microcontroller.
1
uint8 Array[2];
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?
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?

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


Lesenswert?

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.

: Bearbeitet durch Moderator
von Falk B. (falk)


Lesenswert?

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.

von ETK99899 (Gast)


Lesenswert?

Vielen Dank für eure schnellen Antworten und die präzisen Erklärungen.

von Franko P. (sgssn)


Lesenswert?

Andere Möglichkeit ist das union

union v8_16{
uint16 s16;
uint8  a8[2];
};

Gerhard

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


Lesenswert?

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.

von Franko P. (sgssn)


Lesenswert?

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

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


Lesenswert?

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).

von A. S. (Gast)


Lesenswert?

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.

von Franko P. (sgssn)


Lesenswert?

Ah, ok, danke, verstanden.
Gruß
Gerhard

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


Lesenswert?

A. S. schrieb:
> Theoretisch darf er da machen, was er will.

Er muss es aber dokumentieren: es ist "implementation-defined", nicht 
"undefined".

von mh (Gast)


Lesenswert?

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.

von shifty shiff (Gast)


Lesenswert?

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.

von mh (Gast)


Lesenswert?

shifty shiff schrieb:
> Leute, ist es nicht problematisch?

Das ist genauso problematisch wie
1
int foo(int a, int b) {
2
  return a + b;
3
}
je nach Wert von a und b ist es undefined behavior.

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


Lesenswert?

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.

von Falk B. (falk)


Lesenswert?

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.

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.