2016-04-30 18 views
6

Kürzlich cppcheck hob einen Fehler in C-Code, das die Struktur:Ist die Reihenfolge der Auswertung mit Kommaoperator & Zuweisung in C vorhersagbar?

((void)(value_prev = value), value = new_value()) 

In den meisten Fällen kann dies auf zwei Zeilen verteilt werden, jedoch gibt es einige Fälle, dies ist nützlich in einer einzigen Anweisung zu haben.

In der Praxis fand ich, dass dies mit populären Compilern (GCC/Clang/MSVC) funktioniert, die keine Warnungen geben (sogar mit Warnstufen auf ihren höchsten).


Beispielcode:

#include <stdio.h> 

int get_next(int i); 

int main() { 
    int i = 0, i_prev = 10; 
    do { 
     printf("%d\n", i); 
    } while ((void)(i_prev = i), 
      (i = get_next(i)) != 10); 
} 

cppcheck 1,73 (letzte zum Zeitpunkt des Schreibens) einen Fehler mit diesem Code gibt:

(error) Expression '(void)(i_prev=i),(i=get_next(i))!=10' 
depends on order of evaluation of side effects` 

Während der Code zu beruhigen könnte geändert werden Die Warnung, ist die Reihenfolge wirklich undefiniert?

+1

Könnte es sein, dass get_next (i) ein Makro ist, wie #define getnext (i) i ++? – gnasher729

+1

Nein, in diesem Fall ist es als eine Funktion definiert, cppcheck gibt den Fehler in diesem Code ohne irgendwelche Änderungen. – ideasman42

Antwort

8

Die Reihenfolge ist definiert, da zwischen ihnen ein Sequenzpunkt liegt. Siehe ISO/IEC 9899 6.5.17:

Der linke Operand eines Komma-Operator ausgewertet wird als nichtig Ausdruck; Es gibt einen Sequenzpunkt nach seiner Auswertung. Dann wird der rechte Operand ausgewertet; Das Ergebnis hat seinen Typ und Wert. 95) Wenn versucht wird, das Ergebnis eines Kommaoperators zu ändern oder nach dem nächsten Sequenzpunkt darauf zuzugreifen, ist das Verhalten nicht definiert.

sie dann ein explizites Beispiel:

im Funktionsaufruf
f(a, (t=3, t+2), c)
die Funktion hat drei Argumente, von denen die zweite den Wert 5

hat

Ich bin mir nicht ganz sicher, warum CppCheck es markiert.

+0

Ist Sequenzpunkt nicht ein C++ - Ausdruck? – Alex

+0

@Alex Wenn es ist, dann hat C99 es von C++ ausgeliehen. Ich habe keine C-Spezifikationen früher als C99, um zu vergleichen. –