Hallo,
On Sunday 15 July 2001 14:40, Heiko Schlittermann wrote:
vielleicht OT, weil nicht Linux, aber es ist C++ und passiert auch unter Linux ;-)
Also dann, mal wieder den Stroustrup aus dem Regal gekramt....
Hier folgen zwei kleine Programme und ich suche eine plausible Erklärung für die Ausgabe. (Passieren hier undefinierte Dinge? Wenn ja, wo steht, daß es undefiniert ist, was passiert?)
Lt. Stroustrup "Die C++ Programmiersprache", 2. Auflage (dt.), Seite 102, 3.2.2 Auswertungsreihenfolge:
"Die Reihenfolge, in der Unterausdrücke in einem Ausdruck ausgewertet werden, ist undefiniert."
Probiert sowohl mit gcc version 2.95.2 20000220 (Debian GNU/Linux) als auch mit MSCVC++ 6.0. (Wenn ich mich recht erinnere, dann dort mit den selben Resultaten.)
[cut]
Die Resultate für z sind also völlig in Ordnung. Die beiden Compiler haben sich halt entschieden die Sub-Ausdrücke von rechts nach links auszuwerten (siehe Anhang).
Das Resultat für d ist auch ok: d wird hochgezählt, das Ergebnis auf den Stack gelegt und dann multipliziert.
Um das Ergebnis von i zu erklären muss man etwas weiter Richtung Assembler gehen (insbesondere, wenn man den Zusammenhang mit z verstehen will):
Nehmen wir mal an int ist eine Klasse:
class int { public: int& operator++();
int operator*(int&); };
Im Fall z existiert dieser Ausgabeoperator:
ostream& operator<<(ostream&,int);
also wird auf den increment-Operator zurückgegriffen und eine Kopie auf den Stack gelegt, da der Ausgabeoperator nur mit Kopien umgehen kann. Die beiden Kopien enthalten die Werte 6 und 7. In welcher Reihenfolge bleibt dem Compiler überlassen.
Im Fall i existiert ein Multiplikationsoperator, der mit Referenzen umgehen kann. Also wird i zweimal erhöht, es wird aber immer nur eine Referenz gespeichert wird, die dann an dem *-Operator übergeben wird. Ergebnis: der *-Operator löst beide Referenzen auf und bekommt beide male den Wert 7, was zum Ergebnis 49 führt.
Sehr unsauber, äußerst unerwartet aber durchaus im Rahmen der recht lockeren Spezifikationen.
Vielleicht kann das ja einer, der sich als C++-Experte fühlt, mal bitte ausprobieren. Für C-Jünger ist wenigstens noch ein Problem (das erste):
Auch bei C ist vollkommen undefiniert in welcher Reihenfolge Sub-Ausdrücke ausgewertet werden.
Es gibt nur einen Fall in dem es streng definiert ist (zumindest bei C++): die Operatoren && und ||. Deren Ausdrücke _müssen_ von links nach rechts ausgewertet werden. (Was aber einige Compilerbauer nicht davon abhält es trotzdem anders zu machen.)
Konrad