Operatoren Klausurenfrage: Auswertungspräzedenz eines komplizierten Ausdrucks

robinkognito

Mitglied
Hey, ich komme bei einer Altfrage von Programmieren-Klausuren gerade etwas an meine Grenzen. Es geht um folgenden Ausdruck:

int i = 3; i = -++i + (i = i-- - 3);

Ich konnte die Auswertung nun folgendermaßen aufschlüsseln:

  • Zuerst wird der Prefix-Operator auf das i angewendet und wir haben als neuen Wert vor dem Plus durch das unary Minus eine -4.
  • Nun wird die Klammer ausgewertet und dabei der Postfix-Operator auf unsere Variable (i = 4) ausgeführt.
  • Das Dekrementieren von i ist vorgemerkt und die Operation i (4) - 3 wird ausgeführt.
  • Die Variable i wurde verwendet und wird jetzt durch das Postfix --dekrementiert, also i = 3.
  • Aber da der Variable i der Evaluationswert von 4 - 3 zugewiesen wird, "verfällt" der alte Variablenwert und die Auswirkungen des Postfix-Operators sind hinfällig.
  • Abschließend wird -4 + 1 ausgewertet und wir erhalten - 3 als Zuweisung für i.

Was ich dabei nicht kapiere: Wieso wird der Prefixoperator ++ ausgewertet, bevor der Inhalt der Klammer evaluiert wird? Bzgl. der Präzedenz konnte ich da nichts finden, das diesen Umstand erklärt, da Klammern höher gewertet werden sollten als Prefix Plus.
 
Zuletzt bearbeitet:
Int x =1;
Int y = x++;
Erst wird zugewiesen und dann gerechnet
Also y ist 1 und x ist 2


Int y = ++x beide sind 2 erst rechnen dann zuweisen
 
Also bezüglich der Sicht: "Klammern zuerst berechnen" - das ist ein typisch menschliches Vorgehen. Das sieht ein Computer bzw. hier speziell Java nicht so.

Ein wichtiger Punkt in Java ist die Auswertung von links nach rechts. Operanden werden somit von links nach rechts ausgewertet. Das kann man sehr gut bildlich sehen, wenn man einen Ausdruck get(1) + get(2) * get(3); sieht und die Methode get ist einfach:
Java:
    public int get(int value) {
        System.out.println(value);
        return value;
    }

Die Ausgabe ist hier:
1
2
3
Denn die Operanden werden von links nach rechts ausgewertet.

Dann kommt die Berechnung. Dabei ist natürlich 1 + 2 * 3 = 7, denn Multiplikation kommt vor Addition.

Das ++i ist halt im linken Operanden und wird damit zuerst ausgewertet.

Wir können es auch einmal umdrehen, also die Operanden der Addition vertauschen um dann zu schauen, was dann heraus kommt:
int i = 3; i = (i = i-- - 3) - ++i;

Jetzt ist der linke Operand das i=i-- - 3 und das ist dann ein i = 3 - 3 (mit i Variable = 2 durch das --) und dann die Zuweisung von i = 0.
Dann kommt das ++i - damit wird durch den Prefixoperator ++ kurzfristig i = 1 und wir rechnen i = 0 - 1 = -1.

(Was man hier gut sehen kann: Das i-- ist komplett sinnlos, den das weist i ein Wert zu, der dann durch die Zuweisung direkt überschrieben wird. Das aber nur ganz am Rande.)

Hat dies das Vorgehen etwas erläutert? Ist es damit klarer geworden?
 
Mit fällt gerade auf, dass ich in meiner Beschreibung auch teilweise etwas ungenau war.

Also die Klammer gibt ein Teilausdruck, der als ein Operand gesehen wird. Das ist korrekt.

Aber natürlich ist die mathematische Sicht, dass dann das "- ++i" ein Operand der Addition ist, nicht korrekt. Das i ist ein Operand und das - und ++ sind Operatoren. Das spielte jetzt hier bei der Betrachtung aber keine Rolle und das half evtl. auch beim Verständnis, da diese kleine Komplexität heraus genommen wurde. Aber ich denke, es macht auf jeden Fall Sinn, dieses Detail zumindest kurz zu erwähnen. (Aber bitte nicht dadurch verwirren lassen!)

Evtl. ein paar Links, wenn man da etwas nachlesen möchte:
Operatoren mit Rangfolge: Operators (The Java™ Tutorials > Learning the Java Language > Language Basics) (oracle.com)
Dann die Java Language Specification - das ganze Kapitel 15. Das Klammern einen neuen Ausdruck definieren findet sich direkt in 15.8
(Eine PrimaryNoNewArray Expression kann u.a. sein: "( expression )" )
 
Hat dies das Vorgehen etwas erläutert? Ist es damit klarer geworden?

Auf jeden Fall, vielen Dank für die ausführliche Erläuterung!

Das bedeutet also jeder Operand wird für sich von links nach rechts ausgewertet, unabhängig von der Präzedenz im Gesamtkontext?

Also mal ein Beispiel:

Ich habe ++7 + 7++

Hier spielt es dann keine Rolle, dass das Postfix ++ eine höhere Präzedenz als das Prefix ++ aufweist, sondern erst werden von links nach rechts die unären Operationen durchgeführt und anschließend die binären Operationen gemäß ihrer Auswertungsreihenfolge untereinander?
 
Hier spielt es dann keine Rolle, dass das Postfix ++ eine höhere Präzedenz als das Prefix ++ aufweist, sondern erst werden von links nach rechts die unären Operationen durchgeführt und anschließend die binären Operationen gemäß ihrer Auswertungsreihenfolge untereinander?
Betrachten wir das einfach einmal im Detail. Dazu ein konkretes Beispiel (Auf einem Literal kann man kein ++ oder -- Operator anwenden, daher einfach mal mit i bzw. x):
Java:
        int i = 3;
        int x = 3;
        System.out.println( "++i + i-- = " + (++i + i--)  );
        System.out.println("i := " + i);
        System.out.println( "x-- + ++x = " + (x-- + ++x));
        System.out.println("x := " + x);

Code:
++i + i-- = 8
i := 3
x-- + ++x = 6
x := 3


Der wichtige Punkt ist halt nicht nur die operator precedence sondern auch die Assoziativität.

Und da haben wir die links assoziative Addition, d.h. es wird erst der linke Part genommen und dann der rechte.

Du hast das universeller ausgedrückt - mit unären und binären Operatoren und das ist nur eingeschränkt richtig. Es gibt binäre Operatoren, die rechts assoziativ sind: Zuweisungsoperatoren (also =, +=, -=, *=, /=, %=, <<=, >>=, >>>=, &=, ^=, |= ).
(Du meinst aber prinzipiell das Richtige denke ich!)

Evtl. hilft in diesem Zusammenhang auch die Sichtweise weiter, dass die unären Operatoren implizit rechts Assoziativ sind und damit immer nur Elemente rechts von sich beeinträchtigen. Also bei "++i + i--" kann das "i--" keinen Einfluss auf das ++i haben, weil das links vom i-- steht.
 

Zurück
Oben