Was ist das Ergebnis von i == (i = 2)?

Lesezeit: 4 Minuten

Benutzeravatar von kangjianwei
kangjianwei

Führen Sie den folgenden Code aus:

// In Java, output #####
public static void main(String[] args) {
    int i = 1;

    if(i == (i = 2)) {
        System.out.println("@@@@@");
    } else {
        System.out.println("#####");
    }
}

Aber:

// In C, output @@@@@,I did test on Clion(GCC 7.3) and Visual Studio 2017
int main(int argc, char *argv[]) {
    int i = 1;

    if(i == (i = 2)) {
        printf("@@@@@");
    } else {
        printf("#####");
    }

    return 0;
}

Die Motivation für diese Frage ergibt sich aus dem folgenden Code:

// The code is from the JDK 11 - java.util.concurrent.atomic.AtomicInteger
// I am curious about the behavior of the variable prev.
public final int getAndUpdate(IntUnaryOperator updateFunction) {
    int prev = get(), next = 0;
    for (boolean haveNext = false;;) {
        if (!haveNext)
            next = updateFunction.applyAsInt(prev);
        if (weakCompareAndSetVolatile(prev, next))
            return prev;
        haveNext = (prev == (prev = get()));
    }
}

Wie lassen sich also die beiden oben genannten unterschiedlichen Ausführungsmodi erklären?

  • Man erklärt sich die zwei unterschiedlichen Ausführungsmodi, indem man zunächst feststellt, dass es sich um zwei völlig unterschiedliche Sprachen handelt. Sie teilen sich zufällig etwas Syntax, aber hier enden die Ähnlichkeiten.

    – StoryTeller – Unslander Monica

    2. Dezember 2018 um 6:44 Uhr

  • Das Ergebnis ist: ein chaotischer Code. Imitieren Sie dies besser nicht, es sei denn, Sie kandidieren für einen Java-Verschleierungswettbewerb.

    – Tristan

    2. Dezember 2018 um 7:29 Uhr

  • Mögliches Duplikat von Logikunterschieden in C und Java

    – Benutzer202729

    2. Dezember 2018 um 8:16 Uhr

  • Undefiniertes Verhalten und Sequenzpunkte

    – phuklv

    2. Dezember 2018 um 16:32 Uhr

  • @TheGreatDuck Nach Ihrer Bearbeitung ist die Frage immer noch gültig und kein Duplikat mehr, aber Die Antwort mit der höchsten Bewertung enthält viele nicht verwandte Teile (und die Anweisung “Zwei Ausführungsmodus” macht keinen Sinn mehr).

    – Benutzer202729

    4. Dezember 2018 um 10:06 Uhr

Antti Haapala -- Benutzeravatar von Слава Україні
Antti Haapala – Слава Україні

Das Verhalten eines C-Programms, das den Ausdruck ausführt i == (i = 2) ist nicht definiert.

Es kommt von C11 6.5p22:

  1. Wenn eine Nebenwirkung auf ein Skalarobjekt relativ zu einer anderen Nebenwirkung auf dasselbe Skalarobjekt oder einer Wertberechnung unter Verwendung des Werts desselben Skalarobjekts nicht sequenziert ist, ist das Verhalten undefiniert. Wenn es mehrere zulässige Reihenfolgen der Unterausdrücke eines Ausdrucks gibt, ist das Verhalten undefiniert, wenn ein solcher nicht sequenzierter Nebeneffekt in einer der Reihenfolgen auftritt.84)

Das i auf der linken Seite von == ist eine Wertberechnung auf dem Wert eines skalaren Objekts i und die rechte Seite i = 2 hat einen Nebeneffekt der Wertzuweisung 2 zu i. Die linke und rechte Seite von == sind untereinander nicht sequenziert. Daher ist das gesamte Programm in C bedeutungslos.

Kompilieren mit gcc -Wall und GCC wird ausspucken:

unsequenced.c:5:16: warning: operation on ‘i’ may be undefined [-Wsequence-point]
     if(i == (i = 2)) {
             ~~~^~~~

Im Gegensatz zu C garantiert Java die Auswertungsauftrag für Operanden (von links nach rechts), also

haveNext = (prev == (prev = get()));

ist in Java richtig. Der Wert von LHS wird strikt bestimmt, bevor die Bewertung der Nebenwirkung auf die RHS erfolgt.

In C du haben um dies als so etwas zu schreiben

newPrev = get();
haveNext = (prev == newPrev);
prev = newPrev;

  • Warum ist i auf der linken Seite eine Wertberechnung? Steht das irgendwo im Standard?

    – Irgendein Name

    2. Dezember 2018 um 6:11 Uhr

  • @SomeName ist natürlich irgendwo im Standard angegeben. 😀

    – Antti Haapala – Слава Україні

    2. Dezember 2018 um 6:11 Uhr

  • Wie wäre es also mit einer Referenz? 🙂 Das einzige, was ich finden konnte, war die value Begriff definiert in 3.19, aber nein value computation dort definiert.

    – Irgendein Name

    2. Dezember 2018 um 6:13 Uhr

  • @SomeName Sie müssen es aus viel zu vielen Stellen in der Prosa ableiten :/ the Fußnote 84 kann jedoch als Abkürzung verwendet werden. Wenn i damals gab es keinen Wert eines Ausdrucks a[i++] = i; würde definiert werden. Fußnoten sind jedoch nicht normativ.

    – Antti Haapala – Слава Україні

    2. Dezember 2018 um 6:34 Uhr


  • @IrgendeinName 5.1.2.3p2 sagt “Wertberechnung des Lvalue-Ausdrucks”, was hier ein Fall ist, i ist ein lvalue und sein Wert muss berechnet werden, da es kein Operand ist. 6.3.2.1p2 sagt “umgewandelt in den Wert, der im bezeichneten Objekt gespeichert ist”, aber dies ist derjenige, auf den sich 5.1.2.3p2 bezieht

    – Antti Haapala – Слава Україні

    2. Dezember 2018 um 6:39 Uhr

Benutzeravatar von Jacob G
Jakob G.

Das Java-Sprachspezifikation (§15.7) Zustände:

Die Programmiersprache Java garantiert, dass die Operanden von Operatoren in einer bestimmten Weise ausgewertet erscheinen Auswertungsauftragnämlich von links nach rechts.

Das Spezifikation (§15.21.1) sagt auch, dass:

Der Wert, der durch die erzeugt wird == Betreiber ist true wenn der Wert des linken Operanden gleich dem Wert des rechten Operanden ist; andernfalls ist das Ergebnis
false.

Daher würde in Java die if-Anweisung zur Laufzeit wie folgt aussehen, was offensichtlich zu ausgewertet wird false:

if (1 == 2) {

}

In C ist es einfach undefiniert (siehe Antwort von Antti).

In C ist das Verhalten von i == (i = 2) ist undefiniert, weil es versucht, ein Objekt zu aktualisieren und den Wert dieses Objekts in einer Berechnung ohne dazwischenliegenden Sequenzpunkt zu verwenden. Das Ergebnis variiert je nach Compiler, Compilereinstellungen und sogar dem umgebenden Code.

1403340cookie-checkWas ist das Ergebnis von i == (i = 2)?

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy