Zuordnung und Zeiger, undefiniertes Verhalten?

8
%Vor%

Ist das ein Beispiel für undefiniertes Verhalten oder hat es mit Sequenzpunkten zu tun? Warum die Linie:

%Vor%

verhält sich nicht wie folgt:

%Vor%

EDIT: Ich habe vergessen zu erwähnen, dass ich die Ausgabe '1234' und 'nil' mit gcc 4.7.

bekomme     
hello_hell 14.06.2013, 18:59
quelle

5 Antworten

5

Die Sprache garantiert Ihnen nicht, dass der rechte Unterausdruck func(&ptr) in

ist %Vor%

wird zuerst ausgewertet, und der linke Unterausdruck *ptr wird später ausgewertet (was offensichtlich der Fall ist, was Sie erwartet haben). Die linke Seite kann zunächst legal ausgewertet werden, vor Aufruf an func . Und genau das ist in Ihrem Fall passiert: *ptr wurde vor dem Aufruf ausgewertet, als ptr noch auf x zeigte. Danach wurde das Zuweisungsziel abgeschlossen (d. H. Es wurde bekannt, dass der Code x zugewiesen wird). Sobald dies geschieht, ändert ptr nicht mehr das Zuweisungsziel.

Das unmittelbare Verhalten Ihres Codes ist daher unspezifiziert aufgrund der nicht angegebenen Reihenfolge der Auswertung. Ein möglicher Evaluierungsplan führt jedoch zu einem undefinierten Verhalten, indem eine Nullzeiger-Dereferenzierung verursacht wird. Dies bedeutet, dass das Verhalten im Allgemeinen undefiniert ist.

Wenn ich das Verhalten dieses Codes in Bezug auf C ++ - Sprache modellieren müsste, würde ich sagen, dass der Evaluierungsprozess in diesem Fall in diese wesentlichen Schritte aufgeteilt werden kann.

%Vor%

(Obwohl die C-Sprache keine Referenzen hat, verwendet sie intern das gleiche Konzept von "run-time bound lvalue", um das Ergebnis der Bewertung der linken Seite der Zuweisung zu speichern.) Die Sprachspezifikation erlaubt genügend Freiheit Schritte 1a und 1b treten in beliebiger Reihenfolge auf. Sie haben erwartet, dass 1b zuerst auftritt, während Ihr Compiler entschied, mit 1a zu beginnen.

    
AnT 14.06.2013, 19:15
quelle
6

Da zwischen den Auswertungen der linken und rechten Seite des Zuweisungsoperators kein Sequenzpunkt existiert, wird nicht angegeben, ob *ptr oder func(&ptr) zuerst ausgewertet wird. Somit ist nicht garantiert, dass die Auswertung von *ptr erlaubt ist, und das Programm hat ein undefiniertes Verhalten.

    
Kerrek SB 14.06.2013 19:12
quelle
5

Das ist undefiniertes Verhalten, glaube ich. Die Norm legt nicht fest, wann das LHS des Auftrags im Vergleich zum RHS bewertet wird. Wenn *ptr nach dem Aufruf der Funktion ausgewertet wird, wird ein Nullzeiger dereferenziert; Wenn es vor dem Aufruf der Funktion ausgewertet wird, erhalten Sie ein vernünftiges Verhalten.

Der Code ist absolut anrüchig. Versuchen Sie nicht, es oder etwas ähnliches in echtem Code zu verwenden.

Beachten Sie, dass unmittelbar vor dem Aufruf einer Funktion ein Sequenzpunkt existiert, nachdem die Argumente ausgewertet wurden. Es gibt auch einen Sequenzpunkt, unmittelbar bevor eine Funktion zurückkehrt. Daher gibt es Sequenzpunkte, die sich auf die Auswertung der Funktionsargumente und deren Rückgabewert beziehen, aber ... und das ist in diesem Kontext entscheidend ... es sagt Ihnen immer noch nicht, ob *ptr vor oder nach der Funktion ausgewertet wird wird genannt. Beides ist möglich; beide sind richtig; Der Code hängt davon ab, was passiert, wodurch er auf undefiniertes Verhalten angewiesen ist.

    
Jonathan Leffler 14.06.2013 19:13
quelle
4

Der Zuweisungsoperator ist kein Sequenzpunkt . Es gibt also keine Garantie , welche Seite zuerst ausgewertet wird. Also ist es nicht spezifiziertes Verhalten.

In einem der Fälle (Dereferenzierung eines NULLPTR) könnte ein undefiniertes Verhalten auftreten.

  

Zwischen aufeinanderfolgenden "Sequenzpunkten" kann der Wert eines Objekts liegen   nur einmal durch einen Ausdruck geändert.

Sie können eine Liste der definierten Sequenzpunkte in C hier sehen .

    
Anirudh Ramanathan 14.06.2013 19:14
quelle
1

Während der Aufruf einer Funktion ein Sequenzpunkt ist, ist dieser an die Auswertung von Parametern (vor dem Aufruf) gebunden, nicht an die Nebeneffekte der Funktionen (der Aufruf selbst).

    
Let_Me_Be 14.06.2013 19:15
quelle