Frage

Vor ein paar Tagen gab es eine Diskussion hier über ob der Ausdruck

i = ++ i +1

ruft UB (undefiniertes Verhalten) auf oder nicht.

Schließlich wurde die Schlussfolgerung gezogen, dass sie UB als Wert von 'I' aufruft, mehr als einmal zwischen zwei Sequenzpunkten.

Ich war in eine Diskussion mit beteiligt Johannes Schaub in demselben Thread. Laut ihm

i = (i, i ++, i) +1 ------ (1) / * ruft auch UB auf * /

Ich sagte (1) nicht auf UB aufgerufen, weil die Nebenwirkungen der vorherigen Unterexpressionen vom Komma -Operator gelöscht werden, 'zwischen i und i ++ und zwischen i ++ und i.

Dann gab er die folgende Erklärung:

"Ja, der Sequenzpunkt nach I ++ vervollständigt alle Nebenwirkungen zuvor, aber es gibt nichts, was den Nebeneffekt der Zuordnung mit dem Nebeneffekt von i ++ überlappt.Das zugrunde liegende Problem besteht Es gibt einen Sequenzpunkt nach und bevor i ++ nicht bedeutet, dass alle Nebenwirkungen in Bezug auf i sequenziert werden.

Beachten Sie auch, dass lediglich ein Sequenzpunkt nichts bedeutet: Die Reihenfolge der Bewertungen wird nicht durch die Form des Code diktiert. Es wird durch semantische Regeln diktiert. In diesem Fall gibt es keine semantische Regel, wenn der Nebeneffekt der Zuordnung bei der Bewertung ihrer Operanden oder Unterexpressionen dieser Operanden auftritt. "

Die in "mutige" geschriebene Aussage verwirrte mich. Soweit ich weiss:

"An bestimmten festgelegten Punkten in der Ausführungssequenz, die als Sequenzpunkte bezeichnet werden, müssen alle Nebenwirkungen früherer Bewertungen vollständig sein, und es müssen keine Nebenwirkungen nachfolgender Bewertungen stattgefunden haben."

Da die Komma -Betreiber auch die Ausführungsreihenfolge angeben ).

Ich möchte also nur wissen, ob (1) UB aufruft oder nicht?. Kann jemand eine andere gültige Erklärung geben?

Vielen Dank!

War es hilfreich?

Lösung

Der C -Standard besagt, dass dies zu Zuordnungsbetreibern (C90 6.3.16 oder C99 6.5.16 Zuweisungsbetreiber):

Der Nebeneffekt der Aktualisierung des gespeicherten Werts des linken Operanden muss zwischen dem vorherigen und dem nächsten Sequenzpunkt erfolgen.

Es scheint mir in der Aussage:

i=(i,i++,i)+1;

Der Sequenzpunkt "vorher" zum Zuordnungsoperator wäre der zweite Komma -Operator und der "nächste" Sequenzpunkt wäre das Ende des Ausdrucks. Ich würde also sagen, dass der Ausdruck nicht undefined Verhalten auftritt.

Dieser Ausdruck:

*(some_ptr + i) = (i,i++,i)+1;

hätte ein undefiniertes Verhalten, da die Reihenfolge der Bewertung der beiden Operanden des Zuordnungsbetreibers undefiniert ist. In diesem Fall ist das Problem nicht, ob der Wert von der Wert des Zuordnungsbetreibers stattfindet Ich habe im linken Griff Operand verwendet, wird vor oder nach der rechten Seite bewertet. Diese Reihenfolge des Bewertungsproblems tritt im ersten Beispiel nicht auf, da in diesem Ausdruck der Wert von i Wird auf der linken Seite nicht verwendet-alles, was der Zuordnungsbetreiber interessiert, ist die "Lvalue-Ness" von von i.

Aber ich denke auch, dass all dies skizzen genug ist (und mein Verständnis der Nuancen ist skizzen genug), dass ich nicht überrascht wäre, wenn mich jemand anders überzeugen kann (in beiden Fällen).

Andere Tipps

Ich glaube, dass der folgende Ausdruck definitiv undefiniertes Verhalten hat.

i + ((i, i++, i) + 1)

Der Grund dafür ist, dass der Komma -Operator Sequenzpunkte zwischen den Unterexpressionen in Klammern angibt, jedoch nicht angeben, wo in dieser Reihenfolge die Bewertung des linken Operanden von + tritt ein. Eine Möglichkeit besteht zwischen den umgebenden Sequenzpunkten i++ und dies verstößt gegen das 5/4 als i wird auf zwei Sequenzpunkte geschrieben, wird aber auch zweimal zwischen denselben Sequenzpunkten gelesen und nicht nur, um den zu speichernden Wert zu bestimmen, sondern auch den Wert des ersten Operanden für die + Operator.

Dies hat auch ein undefiniertes Verhalten.

i += (i, i++, i) + 1;

Jetzt bin ich mir nicht so sicher über diese Aussage.

i = (i, i++, i) + 1;

Obwohl dieselben Prinzipien gelten, gelten, obwohl es gelten, i muss als veränderbarer Lvalue "bewertet" werden und kann dies jederzeit getan werden, aber ich bin nicht überzeugt, dass es es ist Wert ist immer lesen als Teil davon. (Oder gibt es eine andere Einschränkung, dass der Ausdruck verletzt, um UB zu verursachen?)

Die Unterexpression (i, i++, i) geschieht als Teil der Bestimmung des zu gespeicherten Werts und diese Unterexpression enthält einen Sequenzpunkt nach der Speicherung eines Wertes an i. Ich sehe keine Möglichkeit, dass dies die Nebenwirkung von nicht erfordern würde i++ Vor der Bestimmung des zu speichernden Werts und damit des frühesten Punktes, an dem der Nebeneffekt der Zuordnung auftreten kann, vollständig sein.

Nach diesem Sequnce -Punkt iDer Wert wird höchstens einmal und nur gelesen, um den Wert zu bestimmen, an den zurückgelassen wird i, Also ist dieser letzte Teil in Ordnung.

i=(i,i++,i)+1 ------ (1) /* invokes UB as well */

Es ruft kein definiertes Verhalten auf. Die Nebenwirkung von i++ findet vor der Bewertung des nächsten Sequenzpunkts statt, der vom Komma und auch vor der Zuordnung bezeichnet wird.

Schöne Sprache Sudoku. :-)

Bearbeiten: Es gibt eine ausführlichere Erklärung hier.

Ich war am Anfang verwirrt über die Aussage von Johannes (LitB), aber er erwähnte das in:

i = (i, ++i, i) +1

<Johannes>
Wenn <a> Zuordnung ist und ein Inkrement ist. :s: ist ein Sequenzpunkt, dann können die Nebenwirkungen wie folgt zwischen den Sequenzpunkten sequenziert werden: (i :s: i++< a ><n> :s: i) + 1. Der Wert des Skalars i wurde zweimal zwischen dem ersten und zweiten Sequenzpunkt hier verändert. Die Reihenfolge, in der die Zuordnung und das Inkrement auftreten, ist nicht spezifiziert, und da zwischen ihnen keinen Sequenzpunkt gibt, ist sie nicht einmal atomar zueinander. Dies ist eine zulässige Bestellung zulässt, die durch die nicht spezifizierte Reihenfolge dieser Nebenwirkungen zulässig ist.

Dies ist anders als (i++, i++), Da die Bewertungsreihenfolge der beiden Suberxpressionen von links nach rechts und am Sequenzpunkt zwischen ihnen ist, muss das Inkrement der vorherigen Bewertung abgeschlossen sein, und das nächste Inkrement ist noch nicht stattgefunden. Dies ermittelt, dass es keine Änderung des Wertes von gibt i zwischen zwei Sequenzpunkten, die macht (i++, i++) gültig
< /Johannes>

Dies ließ mich der Meinung, dass die von LitB erwähnte Sequenz ungültig ist, weil sie nach C99:

6.5.16.1 (2) In der einfachen Zuordnung (=) wird der Wert des rechten Operands in den Typ des Zuweisungsausdrucks konvertiert und ersetzt den in dem vom linke Operanden angegebenen Objekt.

dh der Wert des rechten Operands muss vor dem Zuordnungs -Nebeneffekt bekannt sein (Änderung des im Objekts entsprechenden Objekts, der dem linken Operanden entspricht)

6.5.17 (2) Der linke Operand eines Kommas -Operators wird als Hohlraumausdruck bewertet; Nach seiner Bewertung gibt es einen Sequenzpunkt. Dann wird der richtige Operand bewertet; Das Ergebnis hat seinen Typ und Wert.

Der IE, der weit rechts von der Komma -Operation, muss bewertet werden, um den Wert und die Art des Komma -Ausdrucks (und den Wert des richtigen Operands für mein Beispiel) zu kennen.

In diesem Fall wäre der "vorherige Sequenzpunkt" für den Nebeneffekt der Zuordnung tatsächlich der rechtswichtige Komma-Betrieb. Die von Johannes erwähnte mögliche Sequenz ist ungültig.

Bitte korrigieren Sie mich, wenn ich falsch liege.


Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top