[c++] Nicht definierte Verhaltens- und Sequenzpunkte


Answers

Dies ist ein Follow-up zu meiner vorherigen Antwort und enthält C ++ 11 verwandtes Material. .

Voraussetzungen : Grundkenntnisse in Beziehungen (Mathematik).

Stimmt es, dass es in C ++ 11 keine Sequenzpunkte gibt?

Ja! Das ist sehr wahr.

Sequenzpunkte wurden in C ++ 11 durch sequenzielle vor und sequenzielle (und nicht sequenzielle und indeterminiert sequenzierte ) relations .

Was genau ist das 'Sequenced Before' Ding?

Sequenced Before (§1.9 / 13) ist eine Beziehung, die lautet:

zwischen Auswertungen, die von einem einzigen thread und induziert eine strikte Teilaufordnung 1

Formal bedeutet das, dass zwei Auswertungen gegeben sind (siehe unten) A und B , wenn A vor B sequenziert wird , dann muss die Ausführung von A der Ausführung von B vorausgehen . Wenn A nicht sequenziert wird, bevor B und B nicht vor A sequenziert sind, sind A und B nicht sequenziert 2 .

Die Auswertungen A und B sind unbestimmt sequenziert, wenn entweder A sequenziert wird, bevor B oder B vor A sequenziert wird, aber es ist nicht spezifiziert, welches 3 .

[ANMERKUNGEN]
1: Eine strikte partielle Ordnung ist eine binäre Beziehung "<" über eine Menge P die Asymmetric und Transitive , dh für alle a , b und c in P gilt:
........(ich). wenn a <b then ¬ (b <a) ( asymmetry );
........ (ii). wenn a <b und b <c, dann a <c ( transitivity ).
2: Die Ausführung von unsymmetrischen Auswertungen kann sich überschneiden .
3: Unbestimmt sequenzierte Auswertungen können nicht überlappen , aber beide könnten zuerst ausgeführt werden.

Was bedeutet das Wort "Evaluation" im Kontext von C ++ 11?

In C ++ 11 umfasst die Auswertung eines Ausdrucks (oder eines Unterausdrucks) im Allgemeinen:

Jetzt (§1.9 / 14) sagt:

Jede Wertberechnung und jeder Nebeneffekt, der mit einem Voll-Ausdruck verknüpft ist, wird vor jeder Wertberechnung und jedem Nebeneffekt, der mit dem nächsten auszuwertenden Voll-Ausdruck verknüpft ist, sequenziert .

  • Triviales Beispiel:

    int x; x = 10; ++x;

    Die Wertberechnung und der mit ++x verbundene Nebeneffekt wird nach der Wertberechnung und dem Nebeneffekt von x = 10; sequenziert x = 10;

Also muss es eine Beziehung zwischen Undefined Behavior und den oben genannten Dingen geben, oder?

Ja! Recht.

In (§1.9 / 15) wurde erwähnt, dass

Sofern nicht anders angegeben, sind Bewertungen von Operanden einzelner Operatoren und von Teilausdrücken einzelner Ausdrücke nicht sequentiell 4 .

Beispielsweise :

int main()
{
     int num = 19 ;
     num = (num << 3) + (num >> 3);
} 
  1. Die Auswertung von Operanden des Operators + ist relativ zueinander unse- quenziert.
  2. Die Auswertung von Operanden von << und >> Operatoren ist relativ zueinander nicht sequentiell.

4: In einem Ausdruck, der während der Ausführung eines Programms mehr als einmal ausgewertet wird, müssen nicht sequenzierte und unbestimmt sequenzierte Auswertungen seiner Unterausdrücke in verschiedenen Auswertungen nicht konsistent durchgeführt werden.

(§1.9 / 15) Die Wertberechnungen der Operanden eines Operators werden vor der Wertberechnung des Ergebnisses des Operators sequenziert.

Das heißt in x + y die Wertberechnung von x und y vor der Wertberechnung von (x + y) sequenziert.

Wichtiger

(§1.9 / 15) Wenn eine Nebenwirkung auf ein Skalarobjekt relativ zu beiden nicht sequenziert ist

(a) eine weitere Nebenwirkung auf dasselbe Skalarobjekt

oder

(b) eine Wertberechnung unter Verwendung des Wertes des gleichen Skalarobjekts.

Das Verhalten ist nicht definiert .

Beispiele:

int i = 5, v[10] = { };
void  f(int,  int);
  1. i = i++ * ++i; // Undefined Behaviour
  2. i = ++i + i++; // Undefined Behaviour
  3. i = ++i + ++i; // Undefined Behaviour
  4. i = v[i++]; // Undefined Behaviour
  5. i = v[++i]: // Well-defined Behavior
  6. i = i++ + 1; // Undefined Behaviour
  7. i = ++i + 1; // Well-defined Behaviour
  8. ++++i; // Well-defined Behaviour
  9. f(i = -1, i = -1); // Undefined Behaviour (see below)

Wenn eine Funktion aufgerufen wird (unabhängig davon, ob die Funktion inline ist oder nicht), wird jede mit einem Argumentausdruck verknüpfte Wertberechnung und Nebenwirkung oder der Postfixausdruck, der die aufgerufene Funktion bezeichnet, vor der Ausführung jedes Ausdrucks oder jeder Anweisung im Hauptteil des Befehls sequenziert aufgerufene Funktion. [ Hinweis: Wertberechnungen und mit verschiedenen Argumentausdrücken verknüpfte Nebenwirkungen sind nicht sequenziell . - Endnote ]

Die Ausdrücke (5) , (7) und (8) rufen kein undefiniertes Verhalten auf. Lesen Sie die folgenden Antworten für eine detailliertere Erklärung.

Letzter Hinweis :

Wenn Sie einen Fehler in der Post finden, hinterlassen Sie bitte einen Kommentar. Power-User (mit Rep> 20000) zögern Sie bitte nicht, den Beitrag zu bearbeiten, um Tippfehler und andere Fehler zu korrigieren.

Question

Was sind "Sequenzpunkte"?

Was ist die Beziehung zwischen undefiniertem Verhalten und Sequenzpunkten?

Ich benutze oft lustige und verschlungene Ausdrücke wie a[++i] = i; um mich besser zu fühlen. Warum sollte ich aufhören, sie zu benutzen?

Wenn Sie dies gelesen haben, besuchen Sie unbedingt die Folgefrage Undefiniertes Verhalten und neu geladene Sequenzpunkte .

(Hinweis: Dies ist ein Eintrag in die C ++ - FAQ von . Wenn Sie die Idee, eine FAQ in diesem Formular bereitzustellen, kritisieren möchten, dann wäre das Posting auf meta, mit dem all dies begonnen wurde , der richtige Ort dafür Diese Frage wird im C ++ - Chatraum überwacht, wo die FAQ-Idee von Anfang an begann, so dass Ihre Antwort sehr wahrscheinlich von denjenigen gelesen wird, die die Idee hatten.)




C ++ 17 ( N4659 ) enthält eine Vorschlagsfeinungsausdruck- Bewertungsreihenfolge für Idiomatic C ++, die eine strengere Reihenfolge der Ausdruckauswertung definiert.

Insbesondere wurde folgender Satz hinzugefügt:

8.18 Zuweisungs- und Verbundzuweisungsoperatoren :
....

In allen Fällen wird die Zuweisung nach der Wertberechnung der rechten und linken Operanden und vor der Wertberechnung des Zuweisungsausdrucks sequenziert. Der rechte Operand wird vor dem linken Operanden sequenziert.

Es macht mehrere Fälle von zuvor undefiniertem Verhalten gültig, einschließlich der in Frage stehenden:

a[++i] = i;

Mehrere andere ähnliche Fälle führen jedoch immer noch zu undefiniertem Verhalten.

In N4140 :

i = i++ + 1; // the behavior is undefined

Aber in N4659

i = i++ + 1; // the value of i is incremented
i = i++ + i; // the behavior is undefined

Natürlich bedeutet die Verwendung eines C ++ 17-kompatiblen Compilers nicht unbedingt, dass man solche Ausdrücke schreiben sollte.






Links