Namespaces
Variants

Order of evaluation

From cppreference.net

Die Reihenfolge der Auswertung der Operanden jedes C-Operators, einschließlich der Reihenfolge der Auswertung von Funktionsargumenten in einem Funktionsaufrufausdruck und der Reihenfolge der Auswertung der Teilausdrücke innerhalb eines Ausdrucks, ist nicht spezifiziert (außer wie unten angegeben). Der Compiler kann sie in beliebiger Reihenfolge auswerten und kann eine andere Reihenfolge wählen, wenn derselbe Ausdruck erneut ausgewertet wird.

In C gibt es kein Konzept von Links-nach-rechts oder Rechts-nach-links Auswertung, was nicht mit der Links-nach-rechts und Rechts-nach-links Assoziativität von Operatoren verwechselt werden darf: Der Ausdruck f1 ( ) + f2 ( ) + f3 ( ) wird aufgrund der Links-nach-rechts-Assoziativität des operator + als ( f1 ( ) + f2 ( ) ) + f3 ( ) geparst, aber der Funktionsaufruf f3 ( ) kann zur Laufzeit zuerst, zuletzt oder zwischen f1 ( ) und f2 ( ) ausgewertet werden.

Inhaltsverzeichnis

Definitionen

Auswertungen

Es gibt zwei Arten von Auswertungen, die vom Compiler für jeden Ausdruck oder Teilausdruck durchgeführt werden (beide sind optional):

  • Wertberechnung  : Berechnung des Werts, der durch den Ausdruck zurückgegeben wird. Dies kann die Bestimmung der Identität des Objekts ( Lvalue-Auswertung ) oder das Lesen eines zuvor einem Objekt zugewiesenen Werts (Rvalue-Auswertung) umfassen.
  • Nebeneffekt  : Zugriff (Lesen oder Schreiben) auf ein durch einen volatile Lvalue bezeichnetes Objekt, Modifikation (Schreiben) eines Objekts , atomare Synchronisation (seit C11) , Modifizieren einer Datei, Ändern der Gleitkommaumgebung (falls unterstützt) oder Aufruf einer Funktion, die eine dieser Operationen durchführt.

Wenn ein Ausdruck keine Nebeneffekte erzeugt und der Compiler feststellen kann, dass der Wert nicht verwendet wird, kann der Ausdruck möglicherweise nicht ausgewertet werden .

Reihenfolge

Sequenced-before ist eine asymmetrische, transitive, paarweise Beziehung zwischen Auswertungen innerhalb desselben Threads (sie kann sich über Threads hinweg erstrecken, wenn atomare Typen und Speicherbarrieren beteiligt sind).

  • Wenn ein Sequence Point zwischen den Teilausdrücken E1 und E2 vorhanden ist, dann sind sowohl Wertberechnung als auch Seiteneffekte von E1 sequenced-before jeder Wertberechnung und jedem Seiteneffekt von E2 .
  • Wenn Auswertung A vor Auswertung B sequenced ist, wird die Auswertung von A abgeschlossen sein, bevor die Auswertung von B beginnt.
  • Wenn A nicht vor B sequenced ist und B vor A sequenced ist, wird die Auswertung von B abgeschlossen sein, bevor die Auswertung von A beginnt.
  • Wenn A nicht vor B sequenced ist und B nicht vor A sequenced ist, dann existieren zwei Möglichkeiten:
    • Auswertungen von A und B sind unsequenced: sie können in beliebiger Reihenfolge ausgeführt werden und können sich überlappen (innerhalb eines einzelnen Ausführungsstrangs kann der Compiler die CPU-Befehle, die A und B umfassen, verschachteln)
    • Auswertungen von A und B sind indeterminately-sequenced: sie können in beliebiger Reihenfolge ausgeführt werden, dürfen sich aber nicht überlappen: entweder wird A vor B abgeschlossen, oder B wird vor A abgeschlossen. Die Reihenfolge kann beim nächsten Auswerten desselben Ausdrucks umgekehrt sein.
(seit C11)

Regeln

1) Es gibt einen Sequenzpunkt nach der Auswertung aller Funktionsargumente und des Funktionsbezeichners und vor dem eigentlichen Funktionsaufruf.
2) Es gibt einen Sequenzpunkt nach der Auswertung des ersten (linken) Operanden und vor der Auswertung des zweiten (rechten) Operanden der folgenden binären Operatoren: && (logisches UND), || (logisches ODER), und , (Komma).
3) Es gibt einen Sequenzpunkt nach der Auswertung des ersten (linken) Operanden und vor der Auswertung des zweiten oder dritten Operanden (je nachdem, welcher ausgewertet wird) des bedingten Operators ?:
4) Es gibt einen Sequenzpunkt nach der Auswertung eines vollständigen Ausdrucks (ein Ausdruck, der kein Teilausdruck ist: typischerweise etwas, das mit einem Semikolon oder einer Steueranweisung von if / switch / while / do endet) und vor dem nächsten vollständigen Ausdruck.
5) Es gibt einen Sequenzpunkt am Ende eines vollständigen Deklarators.
6) Es gibt einen Sequenzpunkt unmittelbar vor der Rückgabe einer Bibliotheksfunktion.
7) Es gibt einen Sequenzpunkt nach der Aktion, die mit jedem Konvertierungsspezifizierer in der formatierten E/A verbunden ist (insbesondere ist es wohlgeformt, wenn scanf verschiedene Felder in dieselbe Variable schreibt und wenn printf dieselbe Variable mehrfach liest und modifiziert oder modifiziert unter Verwendung von % n )
8) Es gibt Sequenzpunkte vor und unmittelbar nach jedem Aufruf einer Vergleichsfunktion durch die Bibliotheksfunktionen qsort und bsearch , sowie zwischen jedem Aufruf der Vergleichsfunktion und der Bewegung der zugehörigen Objekte durch qsort
(seit C99)
9) Die Wertberechnungen (aber nicht die Nebeneffekte) der Operanden jedes Operators sind vor der Wertberechnung des Ergebnisses des Operators (aber nicht dessen Nebeneffekten) sequenziert.
10) Der Nebeneffekt (Modifikation des linken Arguments) des direkten Zuweisungsoperators und aller zusammengesetzten Zuweisungsoperatoren ist nach der Wertberechnung (aber nicht den Nebeneffekten) sowohl des linken als auch des rechten Arguments sequenziert.
11) Die Wertberechnung der Post-Inkrement- und Post-Dekrement-Operatoren ist vor deren Nebeneffekt sequenziert.
12) Ein Funktionsaufruf, der nicht vor oder nach einem anderen Funktionsaufruf sequenziert ist, ist unbestimmt sequenziert (CPU-Befehle, die verschiedene Funktionsaufrufe bilden, können nicht verschachtelt werden, selbst wenn die Funktionen inline sind)
13) In Initialisierungslistenausdrücken sind alle Auswertungen unbestimmt sequenziert
14) Bezüglich eines unbestimmt sequenzierten Funktionsaufrufs sind die Operationen der zusammengesetzten Zuweisungsoperatoren sowie sowohl die Präfix- als auch die Postfix-Formen der Inkrement- und Dekrement-Operatoren einzelne Auswertungen.
(seit C11)

Undefiniertes Verhalten

1) Wenn ein Nebeneffekt auf ein skalares Objekt im Verhältnis zu einem anderen Nebeneffekt auf dasselbe skalare Objekt unsequenziert ist, ist das Verhalten undefiniert .
i = ++i + i++; // undefined behavior
i = i++ + 1; // undefined behavior
f(++i, ++i); // undefined behavior
f(i = -1, i = -1); // undefined behavior
2) Wenn ein Nebeneffekt auf ein skalares Objekt in Bezug auf eine Wertberechnung unter Verwendung des Werts desselben skalaren Objekts ungeordnet ist, ist das Verhalten undefiniert.
f(i, i++); // undefined behavior
a[i] = i++; // undefined behavior
3) Die obigen Regeln gelten, solange mindestens eine zulässige Reihenfolge der Teilausdrücke einen solchen nichtsequenzierten Nebeneffekt erlaubt.

Siehe auch

Operator-Präzedenz die definiert, wie Ausdrücke aus ihrer Quellcode-Darstellung aufgebaut werden.

C++ Dokumentation für Auswertungsreihenfolge