++ operator und präzedenz
-
eh soweit ich weiß ist
int b = (a++ % 2 + a-- == 0);
in c++ nicht definiert.
-
also mit nicht definiert mein ich nicht eindeutig definiert oder?
ich würde gerne GENAUER wissen warum das so passiert und waru mder decrement-operator -- sofort ausgeführt wird. die priorität nach tabelle sagt doch dass
++ oder -- höhere priorität haben als %.
meine frage ist: Sind diese beiden operatoren spezialfälle (seiteneffekte) die sich der präzedenz etwas entziehen?
-
tesss schrieb:
hmm danke aber dann verstehe ich nicht warum der ++ operator in der präzedenztabelle so weit oben steht. dann müsste er doch eigentlich ganz unten stehen oder nicht? mir ist der zusammenhang nicht klar zwischen präzedenztabelle und den seiteneffekten...
Die Präzedenz sagt, welcher Operator zuerst ausgeführt wird. Das ist in diesem Fall operator++(int). Dieser gibt dann den alten Wert zurück, welcher von operator% benutzt wird.
operator-- verhält sich genauso wie operator++. Hast du da vielleicht --a und a-- verwechselt?
Skym0sh0 schrieb:
es ist so, die zeile
int b = (a++ % 2 == 0);
macht folgendes:
a (was gleich 5 ist) wird durch 2 geteilt
Eben nicht! Zuerst wird operator++ ausgewertet.
-
-
aha. heißt dass jetzt dass ++a (oder --a) sofort ausgewertet wreden also hier der neue wert sofort benutzt wird?
-
Sowohl ++a als auch a++ werden sofort ausgewertet, der Rückgabewert ist allerdings unterschiedlich.
-
Noch ne kleine Ergänzung (hatte bei Skym0sh0 vorhin gar nicht so weit gelesen):
Skym0sh0 schrieb:
problematischer wirds bei zeilen wie
int b = (a++ % 2 + a-- == 0);
weil hier a = 5 genutzt wird, dann erhöht wird und dann nochmals genutzt wird und wiederum erniedrigt. nach der zeile ist a wieder 5 aber hat es hat die 6 mal "gesehen" und die 6 wird addiert...
Das ist undefined behaviour, da zwischen a++ und a-- kein Sequenzpunkt liegt.
die preäzedenz tabelle oder prioritäten tabelle hat damit nichts zu tun erstmal
die besagt nur wie stark operatoren binden*this.method(); // * bindet nicht so stark wie der . (*this).method(); // um da sproblem zu umgehen kann man klammern setzen (klammern haben immer die höchste priorität) this->method(); // und weil das zu lang war wurde der pfeil eingeführt
das ist etwa das gleiche thema wie punkt rechnung vor strich rechnung...
Und wo siehst du jetzt den Unterschied zu a++%2?
-
Präzedenzen von Operatorn legen die Gruppierungen fest, also, dass
a*b+c*d
äquivalent zu
(a*b)+(c*d)
ist. Es ist aber nicht festgelegt, welche Unterausdrücke zu erst berechnet werden, sofern es da Freiheiten gibt. Also, a*b kann vor c*d berechnet werden, oder auch anders herum.
Aus
a++ % 2 == 0
wird
((a++) % 2) == 0
aufgrund der Präzedenzen.
Der Postfixoperator ++ ist aber so definiert, dass er den alten Wert zurückgibt und den Wert der Variablen um eins erhöht. Wann das Auslesen von a und Erhöhen von a passiert ist aber wieder nicht festgelegt. Die einzige Ordnung hier ist, dass das Auslesen von a vor der Berechnung des Divisionsrests stattfindet und die Berechnung des Divisionsrests vor dem Vergleich stattfindet (denn: es geht gar nicht anders). So kann der Ausdruck folgendermassen ausgewertet werden:
int olda = a; int divrest = olda % 2; bool ergebnis = divrest == 0; a = olda + 1;
oder auch so:
int olda = a; a = olda + 1; int divrest = olda % 2; bool ergebnis = divrest == 0;
Weil es dem Compiler überlassen wird, in welcher Reihenfolge er den Ausdruck auswertet, darf man hier auch 'a' nicht ein zweites Mal im Ausdruck verwenden, ohne dass ein sogenannter "Sequenzpunkt" dazwischen ist. Beispiel: Bei
(a++)*(a++)
ist das Ergebnis nicht festgelegt. Sequenzpunkte gibt es zB bei den eingebauten Operatoren ?:, && und ||.
Im Gegensatz zum a++ gibt Dir ++a den neuen Wert zurück.
-
krümelkacker schrieb:
So kann der Ausdruck folgendermassen ausgewertet werden:
int olda = a; int divrest = olda % 2; bool ergebnis = divrest == 0; a = olda + 1;
Das denke ich nicht, wenn es um nicht-eingebaute Typen geht(d. h. dass op++(int) auch wirklich als Funktion definiert ist). Denn um olda auf a zu setzen, muss op++(int) aufgerufen werden, sodass
a = olda + 1
bereits am Anfang ausgeführt wird.Bei ints gehe ich allerdings davon aus, dass die obige Reihenfolge vom Compiler gewählt wird, da so die Variable olda überflüssig wird.
-
Michael E. schrieb:
Das denke ich nicht, ...
Ich meinte auch nur den eingebauten ++ Operator. Eine benutzerdefinierte Überladung ist eine Funktion. Ein Funktionsaufruf bringt zwei Sequenzpunkte mit sich, die die Operationen aus dem Funktionskörper einschließen.
Das mit den "Zwischenvariablen" war nur für Demonstrationszwecke bzgl Reihenfolge. Diese Rechnung läuft wahrscheinlich in zwei CPU-Registern ab.
kk
-
@tesss: Kann es sein, dass du auch in der EIPRO-Vorlesung beim Weinzierl bist? xD Der Sedlacek wusste i-wie auch nicht, wie was funktioniert...