Forum: Mikrocontroller und Digitale Elektronik Schieben mit oder ohne cast


Announcement: there is an English version of this forum on EmbDev.net. Posts you create there will be displayed on Mikrocontroller.net and EmbDev.net.
von ETK99899 (Gast)


Bewertung
0 lesenswert
nicht 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


Bewertung
0 lesenswert
nicht 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)


Bewertung
0 lesenswert
nicht 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)


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

von Franko P. (sgssn)


Bewertung
0 lesenswert
nicht lesenswert
Andere Möglichkeit ist das union

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

Gerhard

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


Bewertung
0 lesenswert
nicht 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)


Bewertung
0 lesenswert
nicht 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


Bewertung
0 lesenswert
nicht 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. (achs)


Bewertung
0 lesenswert
nicht 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)


Bewertung
0 lesenswert
nicht lesenswert
Ah, ok, danke, verstanden.
Gruß
Gerhard

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


Bewertung
0 lesenswert
nicht 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)


Bewertung
0 lesenswert
nicht 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)


Bewertung
0 lesenswert
nicht 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)


Bewertung
0 lesenswert
nicht 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


Bewertung
0 lesenswert
nicht 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)


Bewertung
0 lesenswert
nicht 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.

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.