2010-09-01 9 views
12

Ich verwende Coverity Prevent auf ein Projekt, um Fehler zu finden."x = ++ x" ist es wirklich undefiniert?

ein Fehler für diesen Ausdruck (Die Variablennamen sind natürlich geändert) berichtet:

x= 
    (a>= b) ? 
    ++x: 0; 

Die Botschaft lautet:

EVALUATION_ORDER Defekt: In "x=(a>= b) ? ++x: 0;", "x" ist geschrieben in "x" (die Zuordnung LHS) und geschrieben in "(a>= b) ? ++x: 0;" aber die Reihenfolge, in der die Nebenwirkungen stattfinden, ist undefiniert, weil es keinen dazwischenliegenden Sequenzpunkt gibt. ENDE DER NACHRICHT

Während ich verstehen kann, dass "x = x++" undefined ist, ist dieses ein bisschen härter für mich. Ist das ein falsch positives oder nicht?

+1

Der Titel Ihrer Frage ist verwirrend. Sie sagen, dass Sie verstehen, dass 'x = x ++' nicht definiert ist. Der Fragetitel scheint jedoch zu fragen, ob 'x = ++ x' definiert ist. Bedeutet das, dass Sie nicht verstehen, dass 'x = ++ x' nicht definiert ist? Oder ist Ihre Frage tatsächlich über den Fall mit bedingten '?:' Operator? – AnT

+0

Sorry für die Verwirrung. Ich habe verstanden, dass x = x ++ nicht definiert ist, aber nicht (Vergangenheitsform), warum (und wenn) x = ++ x undefiniert ist. Ich habe das nicht geglaubt?: War das Hauptproblem des Problems, deshalb habe ich es weggelassen (leider ohne zu sagen, warum). Aber um die Integrität der Coverity-Nachricht zu bewahren, habe ich sie in der Coverity-Nachricht gespeichert. Ich stimme zu, dass dies meine Frage ein wenig verwirrend gemacht hat. –

+0

Ist dies auch für JAVA undefiniert? Weil ich hier http://www.careercup.com/question?id=13543663 sehe und der am meisten upgestimmte ans vorschlägt, dass es eine definierte Ausgabe geben wird. – user007

Antwort

28

Konditionaloperator ?: hat eine Sequenz Punkt zwischen Auswertung der Bedingung (erster Operand) und Auswertung der zweiten oder dritten Operanden, aber es hat keine spezielle Sequenzpunkt nach die Auswertung der zweiten oder dritten Operanden. Dies bedeutet, dass zwei Modifikationen von x in diesem Beispiel potentiell widersprüchlich sind (nicht durch einen Sequenzpunkt getrennt). So ist Coverity Prevent richtig.

Ihre Aussage in dieser Hinsicht nahezu gleichwertig

a >= b ? x = ++x : x = 0; 

mit dem gleichen Problem wie in x = ++x.

Nun scheint der Titel Ihrer Frage darauf hinzuweisen, dass Sie nicht wissen, ob x = ++x nicht definiert ist. Es ist in der Tat undefiniert. Es ist aus dem gleichen Grund nicht definiert x = x++ ist undefiniert. Kurz gesagt, wenn das gleiche Objekt mehr als einmal zwischen einem Paar benachbarter Sequenzpunkte modifiziert wird, ist das Verhalten undefiniert. In diesem Fall wird x durch Zuweisung modifiziert und durch ++ gibt es keinen Sequenzpunkt, um diese Modifikationen voneinander zu "isolieren". Also, das Verhalten ist nicht definiert. Es gibt absolut keinen Unterschied zwischen ++x und x++ in dieser Hinsicht.

+0

+1: Bin überrascht, warum Comeau Online keinen Fehler für diesen Fall oder den einfachen Fall von "x = x ++;" – Chubsdad

+0

@chubsdad: Ich kann mich nicht erinnern, dass Comeau Online jemals solche Situationen erwischt hat. GCC ist dafür bekannt, dass es in solchen Fällen Warnungen ausgibt, aber es klagen nicht über den '?:' Fall. – AnT

+0

Ist dies auch für JAVA undefiniert? Weil ich hier http://www.careercup.com/question?id=13543663 sehe und der am meisten upgestimmte ans vorschlägt, dass es eine definierte Ausgabe geben wird. – user007

12

Unabhängig von der Genauigkeit der Nachricht, das Ersetzen des betreffenden Codes durch x= (a>= b) ? x+1: 0; erreicht das gleiche Ende ohne jede Verwirrung. Wenn das Tool verwirrt ist, dann wird vielleicht auch die nächste Person, die sich diesen Code ansieht.

Dies setzt voraus, dass x keinen überladenen Inkrementoperator mit Nebenwirkungen hat, auf die Sie sich hier verlassen.

+0

Und bitte, aus der Güte deines Herzens zu anderen Entwicklern, bitte nenne nicht die Dinge 'x',' a' und 'b'. –

+0

@Dominic: Die Frage besagt eindeutig, dass die Namen von den ursprünglichen Namen geändert wurden. –

+0

@Joachim - ach, verpasst, Puh! –

8

Die Anweisung x = ++x; schreibt zweimal auf die Variable x, bevor sie die sequence point trifft und daher ist das Verhalten undefiniert.

3

Es ist schwer, sich einen Compiler vorzustellen, der Code für "x = ++ x;" was in der Tat nicht wie "++ x" funktionieren würde.Wenn x nicht flüchtig ist, wäre es jedoch für einen Compiler zulässig, die Anweisung "y = ++ x;" als

 
    y=x+1; 
    x=x+1; 

Die Anweisung "x = ++ x;" so

 
    x=x+1; 
    x=x+1; 

werden würde das Ziel eines ein arithmetischer Zuweisungsausdruck gewöhnen zu schnell als Quelloperand für eine anderen eine Pipeline-Verzögerung verursachen würde Falls hat, könnte die ehemalige Optimierung sinnvoll sein. Offensichtlich katastrophal, wenn die inkrementierte und die zugewiesene Variable ein und dasselbe sind.

Wenn die Variable 'x' flüchtig ist, kann ich mir keine Code-Sequenz vorstellen, in der ein Compiler, der nicht absichtlich versucht hat, gemein zu sein, "x = x ++;" Als hätte es einen anderen Effekt, als alle Teile von 'x' genau einmal zu lesen und den gleichen korrekten Wert für alle Teile von 'x' genau zweimal zu schreiben.

0

Ich nehme an, dass logisch, wenn Sie entweder "x = ++ x" oder "x = x ++" schreiben, würden Sie das Endergebnis erwarten, dass x ist ein mehr als es begann als. Aber machen Sie es nur ein bisschen komplizierter. Was, wenn du "x = x + (++ x)" geschrieben hast? Ist das das gleiche wie "x = x + (x + 1)"? Oder fügen wir zuerst eins hinzu und fügen dann x zu sich selbst hinzu, d.h. "x = (x + 1) + (x + 1)"? Was, wenn wir "x = (x -) + (x ++)" schreiben?

Selbst wenn Sie eine Sprachspezifikation schreiben könnten, die diesen Konstrukten eine eindeutige Bedeutung verleiht und sie dann sauber implementieren könnte, warum sollten Sie das tun? Ein einzelnes Inkrement in einer Zuweisung zu derselben Variablen zu machen, macht keinen Sinn, und selbst wenn wir es sinnvoll erzwingen, bietet es keine nützliche Funktionalität. Ich bin mir sicher, dass wir einen Kompilierer schreiben könnten, der einen Ausdruck wie "x + 1 = y-1" nehmen würde und herausfinden würden, dass das wirklich "x = y-2" bedeutet, aber warum sollte er sich kümmern? Es gibt keinen Gewinn.

Auch wenn wir Compiler geschrieben haben, die etwas vorhersagbares mit "x = x ++ - ++ x" gemacht haben, müssten Programmierer die Regeln kennen und verstehen. Ohne irgendeinen offensichtlichen Nutzen würde es den Programmen einfach Komplexität hinzufügen, ohne Zweck.

0

Um dies zu verstehen, benötigen Sie ein grundlegendes Verständnis der Sequenzpunkte. Siehe diesen Link: http://en.wikipedia.org/wiki/Sequence_point

Für den Operator = gibt es keinen Sequenzpunkt, es gibt also keine Garantie, dass der Wert von x geändert wird, bevor er erneut x zugewiesen wird.