C: Reihenfolge von Anweisungen im Ausdruck

Gast #5840144
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?
#5840151
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!
#5840156
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
Gast #5840160
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.
#5840178
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.
#5840243
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.
Gast #5840318
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?
Gast #5840360
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.
Gast #5840379
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
Gast #5840388
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.
Gast #5840404
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.

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren