C: Reihenfolge von Anweisungen im Ausdruck

Gast #5840144
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
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
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
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
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
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 #5840308
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.
Gast #5840318
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
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
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
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
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

Eine eigene Frage? Dieser Thread ist über 7 Jahre alt. Stell sie in einem eigenen Thread – dort lesen mehr Leute mit, und sie wird öfter und schneller beantwortet.

Neuen Thread starten

Eine Lösung, Ergänzung oder Rückmeldung zu diesem Thread? Dann antworte hier.

Formatierung
  • [c]C-Code[/c]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] – Link zu einem Artikel
  • Verweis auf einen anderen Beitrag: Rechtsklick auf dessen Beitrags-ID (#8078628), „Adresse kopieren“, in den Text einfügen

Mehr zur Formatierung

Längeren Sourcecode als Anhang, nicht in den Text. JPG nur für Fotos und Scans; Zeichnungen und Screenshots als PNG oder GIF. Siehe Bildformate.

Schon registriert? Anmelden

Wird nicht angezeigt. Wir schicken dir einen Link; sobald du damit bestätigst, erscheint dein Beitrag.

Mit dem Abschicken legst du einen kostenlosen Account an und erkennst die Nutzungsbedingungen und die Datenschutzerklärung an.