Auswertungsreihenfolge
-
Nein, warum sollte es? Flush ist eine Nachricht an den Stream und hat nichts mit dem internen Werkeln des Compilers zu tun.
-
Na die Idee war, dass flush das entleeren des Buffers an dieser Stelle erzwingt und damit ug vor der inkrementierung ausgegeben wird.
-
zachery_foxx schrieb:
Na die Idee war, dass flush das entleeren des Buffers an dieser Stelle erzwingt und damit ug vor der inkrementierung ausgegeben wird.
flush ist ein Ausdruck, wie przif und ug und ug++. Es ist nicht garantiert, dass der Aufruf des op<< vor dem flush ausgewertet wird, bevor przif oder ug++ ausgewertet wird.
-
SeppJ schrieb:
cout << setfill('0') << setw(8) << ug << '.' << przif(ug++) << '\n';Es ist nicht garantiert, in welcher Reihenfolge die Unterausdrücke (also insbesondere
ugundprzif(ug++)) dieses vollständigen Ausdrucks ausgewertet werden.Das würde mich jetzt auch mal interessieren: Sind die diversen << nicht Operatoren, also das, was intern eigentlich nur eine Funktion ist? Und ist die Funktionsaufrufsreihenfolge nicht eindeutig definiert, da ja der Rückgabewert von einer Funktion die nächste aufruft? Müsste nicht garantiert sein, dass zuerst setfill, dann setw, dann ug, dann '.', dann ug++ und dann przif (mit dem alten ug) ausgewertet wird? Denn ansonsten wäre ja nichtmal garantiert, dass er bei
const string target = "Welt"; cout << "Hallo " << target;tatsächlich "Hallo Welt" und nicht "WeltHallo " ausgibt.
-
Die einzelnen Ausdrücke können in beliebiger Reihenfolge ausgewertet werden. Das heisst aber nicht, dass sie nicht zwischengespeichert werden können, um die Reihenfolge dann zu garantieren.
-
Operator << ist nichts besonderes. Denk dir, da stünde + statt << und du willst Strings zusammensetzen:
string stringfunktion1(); string stringfunktion2(); // ... string result = "Hallo " + stringfunktion1() + " 123\n " + stringfunktion2() + " ende";Da steht auch nicht fest, in welcher Reihenfolge stringfunktion1 und stringfunktion2 abgearbeitet werden, trotzdem würdest du nie auf die Idee kommen, dass hinterher die Reihenfolge nicht stimmen würde.
Oder zum Beispiel flush: Das wäre als ob das " 123\n " eine Änderung der Auswertungsreihenfolge erzwingen könnte, bloß weil es eine besondere Bedeutung für die Ausgabe eines Strings auf den Bildschirm hat.Oder auch Grundrechenarten:
int a(); int b(); int c(); // ... int ergebnis = a() + b() * c();Bloß weil die Reihenfolge von a,b und c undefiniert ist, vergisst der Compiler trotzdem nicht, dass Punktrechnung vor Strichrechnung kommt. Und diese Regel erzwingt nicht, dass b und c zuerst ausgewertet werden!
-
Ich habs gerade bei mir getestet.
#include <iostream> #include <cmath> #include <cstdlib> int main(){ using namespace std; //Auswertungsreihenfolge cout<< (!!(cout<<"hello"))+(!!(cout<<"world"))<<'\n';//eingebauter op+ richtig rum cout<< (!!(cout<<"hello"))<<(!!(cout<<"world"))<<'\n';//selbergebauter op<< falsch rum cout<< atan2((!!(cout<<"hello")),(!!(cout<<"world")))<<'\n';//Funktionsaufruf falsch rum cout<< (!!(cout<<"hel"))<<!!(cout<<"lo ")<<(!!(cout<<"world"))<<'\n';//sogar ganz falschrum cout<< atan2(!!(cout<<"hel lo "),!!(cout<<"wor ld"))<<'\n';//Uups, Leiche, übriggeblieben beim Baslt0ln der Folgezeile cout<< atan2(atan2(!!(cout<<"hel"),!!(cout<<"lo ")),atan2(!!(cout<<"wor"),!!(cout<<"ld!")));//auch komplett falsch rum }helloworld2 worldhello11 worldhello0.785398 worldlo hel111 wor ldhel lo 0.785398 ld!worlo hel0.785398
-
Schöner Test. Der g++ bei mir macht's genau so wie bei dir. Der Intercompiler schmeißt 14 Warnungen, von wegen "operands are evaluated in unspecified order" (na sowas
) und macht daraus:helloworld2 hello1world1 helloworld0.785398 hel1lo 1world1 hel lo wor ld0.785398 hello world!0.785398
-
Ich hatte auch g++. Dann fehlt und noch ein MSVC-Lauf.
-
volkard schrieb:
Ich hatte auch g++. Dann fehlt und noch ein MSVC-Lauf.
Falls da kompliziertere Berechnungen laufen, könnte ich mir auch gut vorstellen, dass der Optimierungsgrad eine Rolle spielt.
-
volkard schrieb:
Ich hatte auch g++. Dann fehlt und noch ein MSVC-Lauf.
helloworld2 worldhello11 worldhello0.785398 worldlo hel111 wor ldhel lo 0.785398 ld!worlo hel0.785398Wie oben, musste allerdings noch casten wegen ambiguous call.
-
Bei mir (2005er) ebenfalls. Debug und Release sogar gleich.
-
zachery_foxx schrieb:
Ich bin mir nicht ganz sicher, aber müsste ein "flush" an der richtigen Stelle nicht abhilfe schaffen?
cout << setfill('0') << setw(8) << ug << flush << '.' << przif(ug++) << '\n';Bei meinen Tests mit dem fraglichen Programm hats das tatsächlich getan - aber das kann auch Zufall/Glück sein ...
-
Belli schrieb:
zachery_foxx schrieb:
Ich bin mir nicht ganz sicher, aber müsste ein "flush" an der richtigen Stelle nicht abhilfe schaffen?
cout << setfill('0') << setw(8) << ug << flush << '.' << przif(ug++) << '\n';Bei meinen Tests mit dem fraglichen Programm hats das tatsächlich getan - aber das kann auch Zufall/Glück sein ...
Ja das ist dann Glück. Die richtige Lösung ist aber denkbar simpel: das Ganze in 2 Anweisungen aufgliedern:
cout << setfill('0') << setw(8) << ug << '.'; cout << przif(ug++) << '\n';