Reihenfolge der Auswertung
Die Reihenfolge der Auswertung der Operanden eines beliebigen C-Operators, einschließlich der Reihenfolge der Auswertung von Funktionsargumenten in einem Funktionsaufrufausdruck und der Reihenfolge der Auswertung von Teilausdrücken innerhalb eines beliebigen Ausdrucks ist undefiniert (sofern nicht unten anders angegeben). Der Compiler wertet sie in beliebiger Reihenfolge aus und kann eine andere Reihenfolge wählen, wenn derselbe Ausdruck erneut ausgewertet wird.
Es gibt kein Konzept von Links-nach-Rechts- oder Rechts-nach-Links-Auswertung in C, was nicht mit der Links-nach-Rechts- und Rechts-nach-Links-Assoziativität von Operatoren verwechselt werden darf: Der Ausdruck f1() + f2() + f3() wird wegen der Links-nach-Rechts-Assoziativität des Operators+ als (f1() + f2()) + f3() geparst, aber der Funktionsaufruf an f3 kann zur Laufzeit zuerst, zuletzt oder zwischen f1() oder f2() ausgewertet werden.
Inhalt |
[bearbeiten] Definitionen
[bearbeiten] Auswertungen
Es gibt zwei Arten von Auswertungen, die der Compiler für jeden Ausdruck oder Teilausdruck durchführt (beide sind optional)
- Wertberechnung: Berechnung des Wertes, der vom Ausdruck zurückgegeben wird. Dies kann die Bestimmung der Identität des Objekts (lvalue-Auswertung) oder das Lesen des zuvor einem Objekt zugewiesenen Wertes (rvalue-Auswertung) umfassen.
- Nebeneffekt: Zugriff (Lesen oder Schreiben) auf ein Objekt, das durch ein volatile lvalue bezeichnet wird, Änderung (Schreiben) an einem Objekt, atomare Synchronisation(seit C11), Änderung einer Datei, Änderung der Gleitkommaumgebung (falls unterstützt) oder Aufruf einer Funktion, die eine dieser Operationen ausführt.
Wenn durch einen Ausdruck keine Nebeneffekte erzeugt werden und der Compiler feststellen kann, dass der Wert nicht verwendet wird, wird der Ausdruck möglicherweise nicht ausgewertet.
[bearbeiten] Reihenfolge
"sequenced-before" (sequenziert vor) ist eine asymmetrische, transitive, paarweise Beziehung zwischen Auswertungen innerhalb desselben Threads (sie kann sich über Threads erstrecken, wenn atomare Typen und Speicherbarrieren beteiligt sind).
- Wenn ein Sequenzpunkt zwischen den Teilausdrücken E1 und E2 vorhanden ist, dann sind sowohl die Wertberechnung als auch die Nebeneffekte von E1 *sequenziert vor* jeder Wertberechnung und jedem Nebeneffekt von E2.
|
(seit C11) |
[bearbeiten] Regeln
&& (logisches UND), || (logisches ODER) und , (Komma).?:.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 Ein-/Ausgabe verbunden ist (insbesondere ist es wohlgeformt für scanf, verschiedene Felder in dieselbe Variable zu schreiben, und für printf, dieselbe Variable mehrfach mit %n zu lesen und zu ändern oder zu ändern).
|
(seit C99) |
|
9) Die Wertberechnungen (aber nicht die Nebeneffekte) der Operanden eines beliebigen Operators sind vor der Wertberechnung des Ergebnisses des Operators (aber nicht seiner Nebeneffekte) sequenziert.
10) Der Nebeneffekt (Änderung des linken Arguments) des direkten Zuweisungsoperators und aller zusammengesetzten Zuweisungsoperatoren erfolgt nach der Wertberechnung (aber nicht den Nebeneffekten) sowohl des linken als auch des rechten Arguments.
11) Die Wertberechnung der Postinkrement- und Postdekrementoperatoren ist vor ihrem Nebeneffekt sequenziert.
12) Ein Funktionsaufruf, der nicht vor oder nach einem anderen Funktionsaufruf sequenziert ist, ist unbestimmt sequenziert (CPU-Instruktionen, die verschiedene Funktionsaufrufe darstellen, können nicht verschachtelt werden, auch wenn die Funktionen inlined sind).
13) Bei Initialisierungslisten-Ausdrücken sind alle Auswertungen unbestimmt sequenziert.
14) In Bezug auf einen unbestimmt sequenzierten Funktionsaufruf sind die Operation von zusammengesetzten Zuweisungsoperatoren sowie sowohl Präfix- als auch Postfix-Formen von Inkrement- und Dekrementoperatoren einzelne Auswertungen. |
(seit C11) |
[bearbeiten] Undefiniertes Verhalten
i = ++i + i++; // undefined behavior i = i++ + 1; // undefined behavior f(++i, ++i); // undefined behavior f(i = -1, i = -1); // undefined behavior
f(i, i++); // undefined behavior a[i] = i++; // undefined bevahior
[bearbeiten] Siehe auch
Operatorrangfolge, die definiert, wie Ausdrücke aus ihrer Quellcodedarstellung aufgebaut werden.
| C++ Dokumentation für Reihenfolge der Auswertung
|