Forum: Mikrocontroller und Digitale Elektronik C: Reihenfolge von Anweisungen im Ausdruck


von Klaus Kinski (Gast)


Lesenswert?

Hallo,

mal angenommen ich habe folgenden Ausdruck in einer if Abfrage:

(x>0 && x<9 && x != 200) || x == 2 || (x++ == 2 && --x != 0)

Vermutlich ist die vom Compiler abhängig. Was ist aber, wenn bereits die 
erste Klammer false liefert? Wird dann dann das x++ aus der anderen 
Klammer nicht mehr ausgeführt? Und was passiert, wenn mehrere x++ oder 
--x etc. angegeben werden innerhalb einer Klammer? Von links nach 
rechts?

Und wenn ich folgendes schreibe bekomme ich eine Warnung "suggest 
parentheses around '&&' within '||'", verstehe ich.

x > 0 && x < 10 || x == 100

Wie ist aber die Reihenfolge der Abarbeitung, wenn ich trotzdem keine 
Klammern setze?

von Sven B. (scummos)


Lesenswert?

Nein, in diesem Fall wird immer von links nach rechts ausgewertet. 
Deshalb kann man auch Null-Checks a la "if ( x && *x == 3 )" machen.

von Falk B. (falk)


Lesenswert?

Klaus Kinski schrieb:
> Hallo,
>
> mal angenommen ich habe folgenden Ausdruck in einer if Abfrage:
>
> (x>0 && x<9 && x != 200) || x == 2 || (x++ == 2 && --x != 0)

Was soll der Scheiß? Willst du den C Obfuscation Wettbewerb gewinnen?

> Wie ist aber die Reihenfolge der Abarbeitung, wenn ich trotzdem keine
> Klammern setze?

Gemäß C Prioritäten. Die kennt jeder Compiler. Aber bisweilen nicht 
jeder Programmierer, darum sollten zu besseren Lesbarkeit und 
Eindeutigkeit Klammern gesetzt werden. Aber Pre und Postincrements in 
derartigen logischen Ausdrücken sind ein NOGO!!! Auch wenn es C erlaubt!

von Oliver S. (oliverso)


Lesenswert?

Die Reihenfolge ist nicht compilerabhängig, sondern in C-Standard 
festgelegt. Die Auswertung erfolgt der Reihe nach von links nach rechts.
Bei && wird die Auswertung abgebrochen, sobald ein false auftaucht.

Und x und ein x++ in einem Ausdruck ist per se undefiniertes Verhalten.

Oliver

von Stefan F. (Gast)


Lesenswert?

Ich bin ziemlich sicher, dass alle (jedenfalls alle mir bekannten) 
solche Ausdrücke von links nach rechts abarbeiten und den rechten Teil 
auslassen, sobald das Endergebnis feststeht.

Klammern können diese Reihenfolge ändern.

Aber ob dieses Verhalten garantiert/spezifiziert ist, das weiß ich 
nicht.

von Peter D. (peda)


Lesenswert?

Falk B. schrieb:
> Aber Pre und Postincrements in
> derartigen logischen Ausdrücken sind ein NOGO!!!

Nö, && und || sind sequence points, d.h. die Ausführung der Pre- und 
Postincrements ist eindeutig definiert und daher wird der Compiler auch 
keine Warnung generieren.
Die Klammernwarnung finde ich zu kleinlich.

Der Code ließe sich aber bestimmt deutlich besser verstehbar 
hinschreiben.

von Dirk B. (dirkb2)


Lesenswert?

so wie bei Punkt vor Strichrechnung hat && eine höhere Priorität als ||

https://de.m.wikibooks.org/wiki/C-Programmierung:_Liste_der_Operatoren_nach_Priorität

: Bearbeitet durch User
von Dirk B. (dirkb2)


Lesenswert?

Klaus Kinski schrieb:
> Vermutlich ist die vom Compiler abhängig.

Das steht im Standard.

> Was ist aber, wenn bereits die
> erste Klammer false liefert? Wird dann dann das x++ aus der anderen
> Klammer nicht mehr ausgeführt?

Wenn die erste Klammer true liefert wird die Auswertung abgebrochen, da 
das || dann auch true ergibt
Das x++ bzw —x wird dann nicht mehr ausgeführt.

Das ist die Kurzschlussregelung. Steht auch im Standard.

: Bearbeitet durch User
von mh (Gast)


Lesenswert?

Dirk B. schrieb:
> Steht auch im Standard.

Und in jedem C Lehrbuch.

von zitter_ned_aso (Gast)


Lesenswert?

Klaus Kinski schrieb:
> x > 0 && x < 10 || x == 100
>
> Wie ist aber die Reihenfolge der Abarbeitung, wenn ich trotzdem keine
> Klammern setze?



((x > 0) && (x < 10)) || (x == 100)

von Horst (Gast)


Lesenswert?

Google nach "c operator precedence"

https://en.cppreference.com/w/c/language/operator_precedence

Hier ist das genauestens definiert

von Jürgen W. (Firma: MED-EL GmbH) (wissenwasserj)


Lesenswert?

Das Bedenken hinsichtlich der Inkremente ist gerechtfertigt, da es vom 
Compiler abhängt, ob die Inkremente gemacht werden oder nicht.

Genau deshalb sind gem. MISRA solche Konstruktionen nicht zulässig.

von dunno.. (Gast)


Lesenswert?

Jürgen W. schrieb:
> Genau deshalb sind gem. MISRA solche Konstruktionen nicht zulässig.

Vermutlich auch weil mans beim Review nicht versteht..? :)


Und vermutlich weiß nicht mal der Autor nach ein paar Wochen was das 
Statement soll.
Null wartbarkeit.

von mh (Gast)


Lesenswert?

Jürgen W. schrieb:
> Das Bedenken hinsichtlich der Inkremente ist gerechtfertigt, da es vom
> Compiler abhängt, ob die Inkremente gemacht werden oder nicht.

Es gibt in solchen Fällen 3 Möglichkeiten:
1. Die Inkremente müssen gemacht werden.
2. Die Inkremente dürfen nicht gemacht werden.
3. Es ist undefined behavior und es egal ob das Inkrement gemacht wird 
oder nicht.
Welcher der drei Möglichkeiten in diesem Fall zutrifft legt der C 
Standard fest und die richtige Antwort wurde schon in diesem Thread 
genannt.

> Genau deshalb sind gem. MISRA solche Konstruktionen nicht zulässig.
Bist du sicher? Gibts dafür ne Quelle oder ist das deine Vermutung?

von Jemand (Gast)


Lesenswert?

mh schrieb:
>> Genau deshalb sind gem. MISRA solche Konstruktionen nicht zulässig.
> Bist du sicher? Gibts dafür ne Quelle oder ist das deine Vermutung?

Er nennt doch die relevante Quelle: MISRA C.

>Rule 12.4 (required): The right-hand operand of a logical && or || operator shall 
not contain side effects.

von leo (Gast)


Lesenswert?

Jemand schrieb:
> mh schrieb:
>>> Genau deshalb sind gem. MISRA solche Konstruktionen nicht zulässig.
>> Bist du sicher? Gibts dafür ne Quelle oder ist das deine Vermutung?
>
> Er nennt doch die relevante Quelle: MISRA C.

Naja, MISRA ist nicht der Standard sondern eine Empfehlung. Aber der gcc 
sagt dir eh alles:
1
#include <stdlib.h>
2
#include <stdio.h>
3
4
int main(int argc, char * argv[]) {
5
  int x,y,z;
6
  x = argv[1] ? atoi(argv[1]) : 1;
7
  z = (y = x + 1) + x++;
8
  printf("x = %d y = %d z = %d\n", x, y, z);
9
  return y;
10
}
1
$ gcc -Wall if.c && ./a.out
2
if.c: In function ‘main’:
3
if.c:7:22: warning: operation on ‘x’ may be undefined [-Wsequence-point]
4
   z = (y = x + 1) + x++;
5
                     ~^~
6
x = 2 y = 2 z = 3

D.h. der gcc warnt davor, dass entweder x++ oder die Zuweisung zu y 
zuerst ausgefuehrt werden koennte.

"Short-circuit evaluation" ist ganz was anderes und bestimmt.

leo

von mh (Gast)


Lesenswert?

Jemand schrieb:
> mh schrieb:
>>> Genau deshalb sind gem. MISRA solche Konstruktionen nicht zulässig.
>> Bist du sicher? Gibts dafür ne Quelle oder ist das deine Vermutung?
>
> Er nennt doch die relevante Quelle: MISRA C.
>
>>Rule 12.4 (required): The right-hand operand of a logical && or || operator 
shall
> not contain side effects.

Es geht mir nicht um die Regel selbst, sondern um die Rechtfertigung der 
Regel, das "Genau deshalb".

leo schrieb:
> D.h. der gcc warnt davor, dass entweder x++ oder die Zuweisung zu y
> zuerst ausgefuehrt werden koennte.

Das ist aber ein neues Beispiel und hat nichts mit dem Rest des Threads 
zu tun.

von leo (Gast)


Lesenswert?

mh schrieb:
> Das ist aber ein neues Beispiel und hat nichts mit dem Rest des Threads
> zu tun.

Aber nein, das behandelt nur deinen 3. Fall und verdeutlicht vom TO:
1
 ... (x++ == 2 && --x != 0)


leo

von Jibi (Gast)


Lesenswert?

Early Expression validation, ist c standart

von mh (Gast)


Lesenswert?

leo schrieb:
> mh schrieb:
>> Das ist aber ein neues Beispiel und hat nichts mit dem Rest des Threads
>> zu tun.
>
> Aber nein, das behandelt nur deinen 3. Fall und verdeutlicht vom TO: ...
> (x++ == 2 && --x != 0)
>
> leo

Ich verstehe nicht was du meinst. Das Beispiel vom TO ist "OK", also 
nach dem C Standard ist das Verhalten definiert. Dein Beispiel ist 
einfach UB.

von leo (Gast)


Lesenswert?

mh schrieb:
> Ich verstehe nicht was du meinst.

Ja, rein technisch hast du Recht.

leo

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.