Fällt dieser Code in C in die Kategorie "Undefiniertes Verhalten"?

7

a ist ein Array, foo ist eine Funktion und i ist ein int .

%Vor%

Würde der obige Code ein Undefiniertes Verhalten haben?

Die Array-Indizes ++i , i-1 und i befinden sich garantiert im Array-Bereich.

    
Bite Bytes 21.08.2017, 18:03
quelle

4 Antworten

7

Das Verhalten ist nicht definiert, aber es liegt nicht an der zweimaligen Änderung desselben Objekts zwischen zwei Sequenzpunkten, sondern an UB, da die Nebenwirkung auf i relativ zu der Wertberechnung von a[i-1] und% co_de nicht ausgeglichen ist % mit a[i] .

§6.5-p (2):

  

Wenn ein Nebeneffekt auf ein Skalarobjekt relativ zu ungleich ist, wird entweder ein anderer Nebeneffekt auf dasselbe Skalarobjekt oder eine Wertberechnung unter Verwendung des Werts des gleichen Skalarobjekts das Verhalten ist undefiniert . Wenn es mehrere zulässige Ordnungen der Teilausdrücke eines Ausdrucks gibt, ist das Verhalten undefiniert, wenn solch ein nicht-sequenzierter Nebeneffekt in irgendeiner der Reihenfolgen auftritt. 84

Zum Beispiel Ausdruck

%Vor%

ruft undefiniertes Verhalten auf. Gleiches gilt für

%Vor%     
haccks 21.08.2017, 18:30
quelle
5

Gemäß dem C-Standard (6.5.16 Zuweisungsoperatoren):

  

Semantik

     

3 ... Die Auswertungen der Operanden sind unsequenced .

Also diese Aussage

%Vor%

führt zu undefiniertem Verhalten.

    
Vlad from Moscow 21.08.2017 18:08
quelle
4

Ja, es ist ein nicht definiertes Verhalten.

Nicht, weil man nicht zwischen zwei Sequenzpunkten zu denselben Variablen lesen und schreiben darf, sondern wegen der Regel, dass

  

Zwischen zwei beliebigen Sequenzpunkten sollten alle Lesevorgänge einer Variablen direkt beim Berechnen des Ergebnisses des Schreibens in dieselbe Variable verwendet werden.

Hier ist der Schreibvorgang in i i++ . Das Lesen derselben Variablen befindet sich in den Argumenten. Obwohl Funktionsaufruf ein Sequenzpunkt ist, ist die Zuweisung nicht. Daher kann die Bewertung des Array-Index vor der Bewertung von RHS erfolgen.

Das Lesen von i in foo(a[i-1], a[i]) trägt nicht direkt zum Schreiben bei und daher ist es UB.

Die relevanten Teile des C99-Standards sind 6.5 Ausdrücke, §2

  

Zwischen dem vorherigen und dem nächsten Sequenzpunkt darf ein gespeicherter Wert eines Objekts höchstens einmal durch die Auswertung eines Ausdrucks geändert werden. Darüber hinaus darf der vorherige Wert nur gelesen werden, um den zu speichernden Wert zu bestimmen.

(Betonung meiner)

    
Ajay Brahmakshatriya 21.08.2017 18:31
quelle
3

Das Verhalten ist nicht definiert, weil die Ausdrücke a[++i] , a[i-1] und a[i] relativ zueinander nicht sequenziert sind.

Kapitel und Verse:

6.5 Ausdrücke
...
2 Wenn ein Nebeneffekt auf ein Skalarobjekt nicht sequenziert ist, relativ zu einem anderen Nebeneffekt auf demselben Skalarobjekt oder einer Wertberechnung unter Verwendung des Werts desselben Skalars Objekt, das Verhalten ist nicht definiert. Wenn mehrere zulässige Ordnungen der Teilausdrücke eines Ausdrucks, das Verhalten ist nicht definiert, wenn eine solche unse- quenzierte Seite vorliegt Effekt tritt in irgendeiner der Ordnungen auf. 84
...
6.5.2.2 Funktionsaufrufe
...
10 Es gibt einen Sequenzpunkt nach den Auswertungen des Funktionsbezeichners und des tatsächlichen Argumente, aber vor dem eigentlichen Aufruf. Jede Auswertung in der aufrufenden Funktion (einschließlich andere Funktionsaufrufe), die vor oder nach dem Die Ausführung des Körpers der aufgerufenen Funktion ist unbestimmt sequenziert in Bezug auf die Ausführung der aufgerufenen Funktion. 94
...
6.5.16 Zuweisungsoperatoren
...
3 Ein Zuweisungsoperator speichert einen Wert in dem durch den linken Operanden bezeichneten Objekt. Ein Der Zuweisungsausdruck hat den Wert des linken Operanden nach der Zuweisung, 111 aber nicht ein Wert. Der Typ eines Zuweisungsausdrucks ist der Typ, den der linke Operand haben würde nach Lvalue-Konvertierung. Der Nebeneffekt der Aktualisierung des gespeicherten Wertes des linken Operanden ist nach den Wertberechnungen der linken und rechten Operanden sequenziert. Die Bewertungen von Die Operanden sind nicht sequenziert. 84) Dieser Absatz rendert nicht definierte Anweisungsausdrücke wie zB
    i = ++i + 1;
    a[i++] = i;
während es erlaubt %Vor% ...
94) Mit anderen Worten, Funktionsausführungen verschachteln sich nicht miteinander ...
111) Die Implementierung darf das Objekt lesen, um den Wert zu bestimmen, muss es aber nicht einmal wenn das Objekt den Typ "flüchtig" aufweist.

C 2011 Online-Entwurf

    
John Bode 21.08.2017 18:47
quelle