interessantes phänomen



  • Hmm, kann es sein, dass das undefiniertes Verhalten ist? Wo sind die Sprachjustiziare hier? 😉

    Zur Information für die anderen: Bei mir kommt 1032 raus.

    @CppProgger
    Klammer mal den cout Ausdruck ordentlich, dann sollte es klar werden.



  • Die << Kette wird ja von hinten aufgerollt, weil der Stream immer an das nächste Objekt übergeben werden soll. Also ist die Ausgabe doch korrekt?!



  • Hi,

    ich hab es auch schon geklammert und dann funktioniert es auch erwartungsgemäß aber ich verstehe nicht wieso C++ das an dieser Stelle macht ohne Klammern.

    Der << operator wird doch von links nach rechts ausgeführt, anders geht es ja eigentlich auch nicht weil er ja immer ein ostream objekt zurückliefern muss für den folgenden << operator. Und genau hier versteh ich es nicht mehr.

    Der erste << operator erhält ja cout und 0 und liefert cout mit dem hineingeschriebenen 0er wieder zurück, jetzt kommt der nächste << Aufruf mit dem cout objekt das bereits die 0 enthält und sollte jetzt die 1 anhängen. Aber es läuft genau anders herum?!

    Ist mir zu hoch...



  • Ne, von rechst nach links.





  • Ah, und bei

    cout << 1 << 2 << 3;

    wird dann 321 ausgegeben?

    Und wenn er von rechts nach links aufrollen würde, wie sollte das denn dann aussehen der operator ist ja so überladen

    ostream& operator<<(ostream&, <T>);

    Es gibt doch nur sinn wenn er von links nach rechts ausgeführt wird.

    Ciao



  • David_pb schrieb:

    Ne, von rechst nach links.

    Nein, links nach rechts. Das steht in jedem Anfängerbuch, außerdem wär das ziemlich widersinnig, weil der Stream dann intern die Ausgaben umdrehen müsste. Wieso beharrst du auf diesem Unsinn?



  • pale dog schrieb:

    http://home.fnal.gov/~wb/Expressions.html
    🙂

    Is hier egal ob pre oder postinkrement verwendet wird. Die Reihenfolge bleibt trotzdem gleich! 😉



  • Bashar schrieb:

    David_pb schrieb:

    Ne, von rechst nach links.

    Nein, links nach rechts. Das steht in jedem Anfängerbuch, außerdem wär das ziemlich widersinnig, weil der Stream dann intern die Ausgaben umdrehen müsste. Wieso beharrst du auf diesem Unsinn?

    Probiers doch aus:

    int foo( int i )
    {
    	std::cout << "i=" << i << std::endl;
    	static int x = 0;
    	return ++x;
    }
    
    int main()
    {
    	std::cout << foo(1) << " " << foo(2) << " ";
    
    	std::cin.get();
    }
    


  • Die Reihenfolge der Abarbeitung der Teilausdrücke ist unspezifiziert, die hat nichts mit der Assoziativität der Operatoren zu tun.



  • Bashar schrieb:

    Die Reihenfolge der Abarbeitung der Teilausdrücke ist unspezifiziert, die hat nichts mit der Assoziativität der Operatoren zu tun.

    Aber mit dem Problem hier!



  • Aha. Eben hast du noch gesagt die Assoziativität wäre von rechts nach links. Das Problem hier ist in der Tat die unspezifizierte Abarbeitungsreihenfolge. Die gilt generell für alle Operatoren außer (nicht überladenen) &&, ||, Komma und ?:. Hauptsache das Ergebnis eines Teilausdruckes steht zur Verfügung wenn es benötigt wird.



  • das erinnert mich an meine informatik/Programmier vorlessungen in C++ da muss man auch das verhalten und Ausgaben anhand solcher Code Beispiele angeben;) nur noch bischen krassere block strukturen etc.



  • nun,bei mir läufts so wie erwartet (0123)
    komischen compiler hast du dann wohl



  • seltsam schrieb:

    nun,bei mir läufts so wie erwartet (0123)
    komischen compiler hast du dann wohl

    Was für einen Compiler hast du denn? Der gcc und Visual C++ bringen bei mir die Ausgabe 3210.



  • Also mit dem Borland 6 krieg ich 1032 raus.

    Versteh das aber net ganz. Ich mein die Funktion foo() wird doch jedesmal
    neu gestartet, da müsste doch immer das selbe zurückkommen 😕

    Was meint ihr eigentlich mit Cout richtig klammern? Versteh net ganz was da geklammert werden soll 😕



  • Schau dir nochmal an was static macht! 😉



  • Verstehs auch nicht!
    Ich bekomme "0132" ???
    Mit VC80



  • Das ist einfach undefiniertes Verhalten. Das ist vergleichbar mit:

    j = ++i + ++i;
    

    Das lernt man eigentlich in jedem C- oder C++-Grundkurs. Wann welcher Teilausdruck ausgewertet wird ist nicht definiert. Das hat nichts mit komischen Compilern zu tun, sondern ist einfach nicht definiert. Der Compiler kann sich entscheiden, zuerst die foo()-Aufrufe in welcher Reihenfolge auch immer auszuwerten und dann die operator<<-Aufrufe.



  • Dann wollen wir das mal aufdröseln:

    cout<<foo()/*1*/<<foo()/*2*/;
    
       =
    
    operator<<(
      opoperator<<(
        cout,
        foo()/*1*/
      ),
      foo()/*2*/
    );
    

    Es ist klar definiert, daß alle benötigten Teilausdrücke berechnet werden, bevor sie zusammenkommen - insbesondere wird der innere op<<-Aufruf und der zweite foo() ausgeführt, bevor der äußere op<< drankommen kann. Aber es ist nicht vorgeschrieben, in welcher Reihenfolge die Parameter einer Funktion berechnet werden, also steht es einem Compiler frei, erst den unteren foo()-Aufruf und danach den inneren op<< abzuarbeiten (oder auch umgekehrt) - im ersten Fall lautet das Ergebnis "10", im letzten Fall "01".
    (klarer Fall von undefniertem Verhalten)


Anmelden zum Antworten