Forum: Compiler & IDEs return uart_rx() | (uart_rx() << 8);


von Bernd K. (prof7bit)


Lesenswert?

Darf der Compiler die Reihenfolge der Funktionsaufrufe vertauschen?
1
uint16_t uart_rx16(void) {
2
  return uart_rx() | (uart_rx() << 8);
3
}

von nicht“Gast“ (Gast)


Lesenswert?

Ja, die Reihenfolge ist nicht festgelegt

von Peter D. (peda)


Lesenswert?

Ja, | ist kein Sequence point.

von Bernd K. (prof7bit)


Lesenswert?

Peter D. schrieb:
> Sequence point

Danke! Das war das Stichwort.

von Uwe B. (Firma: TU Darmstadt) (uwebonnes)


Lesenswert?

Trifft das auch zu, wenn uart_rx() als volatile deklariert ist?

von (prx) A. K. (prx)


Lesenswert?

ja

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

Uwe B. schrieb:
> Trifft das auch zu, wenn uart_rx() als volatile deklariert ist?

Es ist nicht möglich, eine Funktion als volatile zu definieren.

von Mark B. (markbrandis)


Lesenswert?

Bernd K. schrieb:
> Darf der Compiler die Reihenfolge der Funktionsaufrufe vertauschen?
>
>
1
> uint16_t uart_rx16(void) {
2
>   return uart_rx() | (uart_rx() << 8);
3
> }
4
>

Gegenfrage:
Ist ein zweimaliger Aufruf von uart_rx() wirklich das, was man an dieser 
Stelle haben will? Oder war es eher so gemeint:

1
uint16_t uart_rx16(void) {
2
  uint16_t temp = uart_rx();
3
  return temp | (temp << 8);
4
}

: Bearbeitet durch User
von Johann L. (gjlayde) Benutzerseite


Lesenswert?

Nein, eine Multiplikation mit 257 war nicht gemeint.

Der TO will einen 16-Bit Wert aus zwei 8-Bit Werten zusammenbastelt, die 
über den UART empfangen wurden.  Und da macht es eben einen Unterschied, 
wo LSB und MSB im 16-Bit Ergebnis landen.

von Mark B. (markbrandis)


Lesenswert?

Johann L. schrieb:
> Nein, eine Multiplikation mit 257 war nicht gemeint.
>
> Der TO will einen 16-Bit Wert aus zwei 8-Bit Werten zusammenbastelt, die
> über den UART empfangen wurden.  Und da macht es eben einen Unterschied,
> wo LSB und MSB im 16-Bit Ergebnis landen.

Ach so. Also sowas hier dann:

1
uint16_t uart_rx16(void)
2
{
3
    uint8_t lo_byte = uart_rx();
4
    uint8_t hi_byte = uart_rx();
5
    return (hi_byte << 8) | lo_byte;
6
}

Und schon stellt sich die ursprüngliche Frage gar nicht mehr, weil man 
saubere Sequence Points hat.

Für mich ein typischer Fall von "Quetsch nicht so viel Code in eine 
Zeile, dann lösen sich viele Probleme von ganz alleine".

von Falk B. (falk)


Lesenswert?

Premature optimization is the root of all evil.

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

Falk B. schrieb:
> Premature optimization is the root of all evil.

Mit Optimierung hat das nix zu tun, eher mit "Know your Language!"

von Mark B. (markbrandis)


Lesenswert?

Johann L. schrieb:
> Mit Optimierung hat das nix zu tun

In der Vorstellung mancher Menschen schon:
"Wenn ich möglichst wenig Code schreibe, dann ist das optimal. Also 
quetsche ich möglichst viele Anweisungen in eine Zeile, anstatt das 
Ganze auszuschreiben."

: Bearbeitet durch User
von Yalu X. (yalu) (Moderator)


Lesenswert?

Mark B. schrieb:
> "Wenn ich möglichst wenig Code schreibe, dann ist das optimal. Also
> quetsche ich möglichst viele Anweisungen in eine Zeile, anstatt das
> Ganze auszuschreiben."

Der Ausdruck enthält gerade einmal zwei Operationen (| und <<). Das ist
IMHO nicht gequetscht, sondern die ganz natürliche Schreibweise für so
etwas. Etwa vergleichbar wäre

1
  return gain * x + offset;

Das würde auch niemand (außer den BASCOM-Programmierern ;-)) in mehrere
Zeilen aufdröseln:

1
  int gainedValue = gain * x;   // unnötig
2
  return gainedValue + offset;  // kompliziert

Der einzige Grund, warum man die Codezeile

1
  return uart_rx() | (uart_rx() << 8);

in zwei Anweisungen aufsplitten muss, ist der mehrfache Aufruf der
nebeneffektbehafteten Funktion uart_rx, deren Aufrufreihenfolge sonst
nicht definiert ist.

von Mark B. (markbrandis)


Lesenswert?

Yalu X. schrieb:
> Der einzige Grund, warum man die Codezeile
>
>
>
1
>   return uart_rx() | (uart_rx() << 8);
2
>
>
> in zwei Anweisungen aufsplitten muss, ist der mehrfache Aufruf der
> nebeneffektbehafteten Funktion uart_rx, deren Aufrufreihenfolge sonst
> nicht definiert ist.

Und der Grund warum dies nicht getan wurde ist, dass der Programmierer 
meint dies in eine Zeile quetschen zu müssen.

q.e.d.

von Yalu X. (yalu) (Moderator)


Lesenswert?

Mark B. schrieb:
> Und der Grund warum dies nicht getan wurde ist, dass der Programmierer
> meint dies in eine Zeile quetschen zu müssen.

Ich glaube nicht, dass er unter irgendwelchen Zwängen steht.

Deswegen hat er ja nachgefragt, ob man das so machen kann, und nach den
ersten beiden Antworten auch sofort eingesehen, dass es so nicht geht.

Kritisieren solltest du also nicht ihn, sondern diejenigen, die solche
Konstrukte in ihren Code einbauen, ohne sich vorher zu vergewissern,
dass sie korrekt sind.

von Tom (Gast)


Lesenswert?

Yalu X. schrieb:
> ohne sich vorher zu vergewissern,
> dass sie korrekt sind.

Und wenn man sich bei einem Konstrukt erst vergewissern muss, dass es 
korrekt ist, ist es zu kompliziert.

von Falk B. (falk)


Lesenswert?

@ Yalu X. (yalu) (Moderator)

>Deswegen hat er ja nachgefragt, ob man das so machen kann, und nach den
>ersten beiden Antworten auch sofort eingesehen, dass es so nicht geht.

Ein guter Compiler sollte da mindestens eine Warung ausspucken. Gute 
Programmiersprachen lassen solche Konstrukte gar nicht erst zu ;-)

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


Lesenswert?

Tom schrieb:
> Und wenn man sich bei einem Konstrukt erst vergewissern muss, dass es
> korrekt ist, ist es zu kompliziert.

Wem das zu kompliziert ist, der sollte Bascom benutzen. ;-)

: Bearbeitet durch Moderator
von Yalu X. (yalu) (Moderator)


Lesenswert?

Falk B. schrieb:
> Ein guter Compiler sollte da mindestens eine Warung ausspucken.

GCC und Clang tun das jedenfalls nicht, vemutlich deswegen, weil der
Compiler i.Allg. gar nicht erkennen kann, ob eine Funktion Nebeneffekte
hat (bspw. dann, wenn er nur die Funktionssignatur, aber nicht deren
Implementation sieht).

Jörg W. schrieb:
> Wem das zu kompliziert ist, der sollte Bascom benutzen. ;-)

Daran hat ganz sicher auch Falk gedacht, als er schrieb:

Falk B. schrieb:
> Gute Programmiersprachen lassen solche Konstrukte gar nicht erst zu
> ;-)

So arg viel mehr Programmiersprachen, die keine zwei Funktionsaufrufe in
einem Ausdruck zulassen, gibt es nämlich gar nicht¹.

Auch von mir gibt's noch einen Augenzwinker-Smiley dazu: ;-)

———————————
¹) Es gibt aber immerhin welche (z.B. Java), bei denen im Gegensatz zu C
   die Auswertereihenfolge vollständig spezifiziert ist. Da wäre dann
   auch der Ausdruck des TE korrekt.

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.