Inkrementierende Zeiger, genaue Reihenfolge

8

Ich habe gerade angefangen, C zu lernen, und ich verstehe das.

%Vor%

und

%Vor%

sind gleichwertig, aber ist das was tatsächlich passiert, wenn die Zeile

%Vor%

heißt? Kann jemand klären, wie der Compiler die zweite Zeile interpretiert? Ich kenne die Priorität von rechts nach links und so, aber kann jemand genau die Schritte schreiben, die der Compiler verwendet, um diese Codezeile zu interpretieren?

    
pyrrhic 29.07.2013, 14:33
quelle

3 Antworten

12

Sie sagten, dass Sie das glauben:

%Vor%

entspricht

%Vor%

Aber das ist falsch, also hast du einen falschen Glauben. Lass uns deinen falschen Glauben korrigieren.

Im ersten Fall müssen folgende Dinge passieren:

  • VAR: *a muss ausgewertet werden, um eine Variable zu erzeugen, nennen Sie sie var
  • VAL: *b muss ausgewertet werden, um einen Wert zu erzeugen, nennen Sie es val
  • ASSIGN: val muss var zugewiesen werden.
  • INCA: a muss inkrementiert werden.
  • INCB: b muss inkrementiert werden.

Was sind die Einschränkungen für die Reihenfolge, in der der Compiler diese anordnet?

  • VAR und VAL müssen vor ASSIGN auftreten.
  • ASSIGN muss vor INCA stattfinden.
  • INCA muss vor INCB stattfinden.

Die Regel hier ist, dass alle Nebenwirkungen einer Aussage vollständig sein müssen, bevor die nächste Aussage beginnt. Es gibt also zwei rechtliche Ordnungen. VAR VAL ASSIGN INCA INCB oder VAL VAR ASSIGN INCA INCB.

Betrachten wir nun den zweiten Fall.

%Vor%

Wir haben die gleichen fünf Operationen, aber die Einschränkungen für ihre Reihenfolge sind völlig verschieden, da sich alle in derselben Anweisung befinden. Daher gilt die Regel für Anweisungen nicht. Jetzt sind die Einschränkungen:

  • VAR und VAL müssen vor ASSIGN auftreten.
  • Die Bewertung von VAR muss den ursprünglichen Wert von a verwenden
  • die Auswertung von VAL muss den ursprünglichen Wert von b verwenden

Beachten Sie, dass ich nicht gesagt habe, dass die Inkremente später erforderlich sind . Stattdessen habe ich gesagt, dass die ursprünglichen Werte verwendet werden müssen . Solange der ursprüngliche Wert verwendet wird, kann die Erhöhung jederzeit erfolgen.

Zum Beispiel wäre es vollkommen legal, dies als

zu generieren %Vor%

Es wäre auch legal, dies zu tun:

%Vor%

Es wäre auch legal, es so zu machen, wie Sie es vorschlagen: Machen Sie zuerst die Aufgabe und dann beide in der Reihenfolge von links nach rechts. Und es wäre auch legal, die Zuweisung zuerst auszuführen, und dann werden beide von rechts nach links inkrementiert.

Ein C-Compiler hat einen weiten Spielraum, um Code zu erzeugen, wie er auch für diese Art von Ausdruck gefällt. Stellen Sie sicher, dass dies sehr klar ist, weil die meisten Leute das falsch verstehen: nur weil ++ nach der Variable steht, bedeutet das nicht, dass das Inkrement zu spät passiert. Die Erhöhung kann schon so früh wie möglich erfolgen Der Compiler mag , solange der Compiler sicherstellt, dass der ursprüngliche Wert verwendet wird .

Das ist die Regel für C und C ++. In C # erfordert die Sprachspezifikation, dass die Nebenwirkungen der linken Seite einer Zuweisung vor die Nebenwirkungen der rechten Seite einer Zuweisung auftreten, und dass beide vor dem Nebeneffekt der Zuweisung passieren. Derselbe Code in C # wäre erforderlich , um wie folgt generiert zu werden:

%Vor%

Die "Zeigerüberprüfung" ist der Punkt, an dem C # verlangt, dass die Laufzeit überprüft, ob var_a ein gültiger Zeiger ist; mit anderen Worten, dass *var_a tatsächlich eine Variable ist. Wenn dies nicht der Fall ist, muss eine Ausnahme ausgelöst werden, bevor b ausgewertet wird.

Auch hier ist ein C-Compiler erlaubt , um den C # -Weg zu machen, aber nicht erforderlich .

    
Eric Lippert 29.07.2013, 22:07
quelle
4

1)

%Vor%

entspricht

%Vor%

2)

%Vor%

entspricht

%Vor%

und

%Vor%

entspricht

%Vor%

so

%Vor%

entspricht

%Vor%

3)

%Vor%

entspricht

%Vor%     
MOHAMED 29.07.2013 14:40
quelle
3

Die genaue Reihenfolge, in der die Ausdrücke ausgewertet und die Nebenwirkungen angewendet werden, bleibt unspezifiziert ; Alles was garantiert ist, ist, dass das Ergebnis von *b++ (der Wert, auf den b gerade zeigt) dem Ergebnis von *a++ (dem Wert, auf den a gerade zeigt) zugewiesen wird, und dass beide Zeiger fortgeschritten sind . Die genaue Reihenfolge der Operationen wird variieren.

Wenn Sie wissen möchten, wie Ihre Plattform damit umgeht, können Sie sich den generierten Maschinencode ansehen, aber beachten Sie, dass er abhängig von den Compilereinstellungen oder dem umgebenden Code noch variieren kann.

    
John Bode 29.07.2013 16:17
quelle

Tags und Links