Reihenfolge der Auswertung von Funktionen, deren return-Wert als Parameter übergeben wird



  • Warum gibt er die 2 vor der 1 aus? Sollte man nicht meinen, dass Funktionen in der richtigen Reihenfolge aufgerufen werden?

    #include <iostream>
    
    using namespace std;
    
    int Funktion(int i)
    {
    	cout << i << endl;
    
    	return 0;
    }
    
    void F2(int a, int b)
    {
    }
    
    int main()
    {
    	F2(Funktion(1), Funktion(2));
    
    	cin.get();
    }
    


  • Die richtige Reihenfolge ist in diesem Fall, was der Compiler für richtig hält.



  • Nein. Es ist so auch besser da es dem compiler optimierungen erleichtert ... auch bei logschischen (Teil) ausdrücken ist die Reihenfolge nicht geregelt - nur in so fern das midestens alles was nötig ist ausgewertet wird - unter umständen auch mehr aber nie weniger. Die Reihenfolge ist unbestimmt ... meine ich mal gehört zu haben *g*



  • Wenn du dies erstellst wirst du sehen, dass die Reihenfolge unbestimmt ist und der Compiler dir dies optimieren wird:

    #include <iostream> 
    #include <string>
    
    using namespace std; 
    
    int Funktiona(int i) 
    { 
        cout << i << endl; 
    
        return 0; 
    }
    
    int Funktionb(string i) 
    {
        cout << i.c_str() << endl; 
    
        return 0; 
    } 
    
    void F2(int a, int b, int c, int d, int e) 
    { 
    } 
    
    int main() 
    { 
        F2(Funktiona(5), Funktionb("4"), Funktionb("3"), Funktiona(2), Funktiona(1)); 
    
        cin.get();
    	return 0;
    }
    


  • HighLigerBiMBam schrieb:

    Wenn du dies erstellst wirst du sehen, dass die Reihenfolge unbestimmt ist und der Compiler dir dies optimieren wird...

    Nicht, dass er das nicht schon mit seinem Progrämmchen oben festgestellt hätte... 🙄


  • Mod

    padreigh schrieb:

    auch bei logschischen (Teil) ausdrücken ist die Reihenfolge nicht geregelt - nur in so fern das midestens alles was nötig ist ausgewertet wird - unter umständen auch mehr aber nie weniger. Die Reihenfolge ist unbestimmt ... meine ich mal gehört zu haben *g*

    Doch, das ist ganz genau geregelt und wird auch sehr oft ausgenutzt. Ist der linke Teil einer UND-Beziehung schon false, wird der rechte nicht ausgewertet, ist der linke Teil einer ODER-Beziehung schon true, wird der rechte ebenfalls nicht ausgewertet. Andere logische ausdrücke wei ich gerade nicht auswendig, kann man aber nachschlagen. Stichwort: short circuit



  • padreigh schrieb:

    Nein. Es ist so auch besser da es dem compiler optimierungen erleichtert ... auch bei logschischen (Teil) ausdrücken ist die Reihenfolge nicht geregelt - nur in so fern das midestens alles was nötig ist ausgewertet wird - unter umständen auch mehr aber nie weniger. Die Reihenfolge ist unbestimmt ... meine ich mal gehört zu haben *g*

    Die Reihenfolge ist in logischen Ausdrücken sehr wohl geregelt. Das Stichwort zur Reihenfolge heißt "sequence point", siehe z.B. hier: http://en.wikipedia.org/wiki/Sequence_point



  • padreigh schrieb:

    Nein. Es ist so auch besser da es dem compiler optimierungen erleichtert

    Ob das wirklich 'besser' ist, würde ich so pauschal nicht unterschreiben.
    Ist zumindest eine dicke Stolperfalle für Leute, die es von C# oder Java anders kennen.


  • Mod

    Jockelx schrieb:

    Ob das wirklich 'besser' ist, würde ich so pauschal nicht unterschreiben.
    Ist zumindest eine dicke Stolperfalle für Leute, die es von C# oder Java anders kennen.

    Ist das in Java und C# nicht genauso wie in C und C++? Denk daran, dass padreighs Aussage falsch ist, es ist ganz genau geregelt.



  • Die Reihenfolge, in der Funktionsargumente ausgewertet werden, ist ein C und C++ im Gegensatz zu vielen anderen Sprachen unspezifiziert. Wenn du eine definierte Reihenfolge willst, musst du dir Zwischenvariablen anlegen.



  • SeppJ schrieb:

    Ist das in Java und C# nicht genauso wie in C und C++?

    Funktionsargumente werden in Java (und Scheme und Lisp und sicher noch vielen anderen Sprachen) streng von links nach rechts ausgewertet. In der Java-Kopie C# wird das sicher auch so sein.



  • Lustig wirds erst in VB.NET: Da ist Long Circuit Standard. Für Short Circuit darf man nicht And und Or benutzen, sondern AndAlso und OrElse 🤡 Gab ne schöne Exception bei mir.



  • Michael E. schrieb:

    Lustig wirds erst in VB.NET: Da ist Long Circuit Standard.

    Long Circuit? Was ist das für eine Wortkreation? 😃

    Für Short Circuit darf man nicht And und Or benutzen, sondern AndAlso und OrElse 🤡 Gab ne schöne Exception bei mir.

    Das ist in Basic schon immer so, dass And und Or beide Operanden auswerten. AndAlso und OrElse kamen lediglich dazu, um die Shortcut-Semantik auszudrücken. BTW gibts das auch in anderen Sprachen, war es Ada oder Eiffel?, mit and then und or else



  • Bashar schrieb:

    Michael E. schrieb:

    Lustig wirds erst in VB.NET: Da ist Long Circuit Standard.

    Long Circuit? Was ist das für eine Wortkreation? 😃

    Na das Gegenteil von Short Circuit 😉


  • Administrator

    SeppJ schrieb:

    Ist das in Java und C# nicht genauso wie in C und C++?

    In C# jedenfalls nicht. Kann man in der Language Specification nachschauen, welche jedem Visual Studio beiliegen sollte. In VS2010 steht es im Kapitel 7.5.1.2. Die Evaluation erfolgt immer in der Reihenfolge, wie es beim Aufruf hingeschrieben wurde. Das ist zum Beispiel auch bei Named-Arguments wichtig:

    void PrintBoth(int lhs, int rhs)
    {
      Console.WriteLine("{0} {1}", lhs, rhs);
    }
    
    // ...
    int nr = 0;
    PrintBoth(++nr, ++nr);
    PrintBoth(rhs: ++nr, lhs: ++nr);
    

    Die Ausgabe ist garantiert:

    1 2
    4 3
    

    Grüssli



  • Bashar schrieb:

    SeppJ schrieb:

    Ist das in Java und C# nicht genauso wie in C und C++?

    Funktionsargumente werden in Java (und Scheme und Lisp und sicher noch vielen anderen Sprachen) streng von links nach rechts ausgewertet. In der Java-Kopie C# wird das sicher auch so sein.

    Das liegt bei Java vor allem daran, dass es nur eine Plattform gibt für die compiliert wird. Und diese Plattform hat halt ihre festgelegte Auswertereihenfolge.

    Bei Lisp und Scheme kommt das durch die funktionalen Wurzeln dieser Sprachen. Da wäre eine unspezifizierte Auswertereihenfolge extrem kontraproduktiv.

    In Ada gibt es übrigens für Short Circuit eigene Schlüsselwortfolgen. Da muss man A and then B bzw. A or else B schreiben. Ansonsten werden immer alle Ausdrücke ausgewertet.



  • SeppJ schrieb:

    padreigh schrieb:

    auch bei logschischen (Teil) ausdrücken ist die Reihenfolge nicht geregelt - nur in so fern das midestens alles was nötig ist ausgewertet wird - unter umständen auch mehr aber nie weniger. Die Reihenfolge ist unbestimmt ... meine ich mal gehört zu haben *g*

    Doch, das ist ganz genau geregelt und wird auch sehr oft ausgenutzt. Ist der linke Teil einer UND-Beziehung schon false, wird der rechte nicht ausgewertet, ist der linke Teil einer ODER-Beziehung schon true, wird der rechte ebenfalls nicht ausgewertet. Andere logische ausdrücke wei ich gerade nicht auswendig, kann man aber nachschlagen. Stichwort: short circuit

    @manni66: Danke für den Sequencepointlink 🙂

    @SeppJ das wiederspricht meinem ja nicht wirklich, mir war nur unklar ob strengt von links nach rechts ausgewertet wird ...

    bool erg1 = true && true || (komplexes ding das letztendlich false ergeben würde); // (...) wird nicht mehr ausgewertet
    bool erg2 = (false) || true && true;                                               // (...) wird komplett ausgewertet da sequence point, dann || true, (obwohl da ein lookahead massig sparen könnte :) ) dann && true wieder ausgewertet ?
    bool erg3 = (true)  || false && true;                                              // (...) wird komplett ausgewertet, || false wird verworfen und && true wieder ausgewertet ?
    

    Wie siehts aus mit deMorgan ... bastelt der Kompiler da was? Ich will nen Hellseherischen Compiler 😃



  • padreigh schrieb:

    bool erg1 = true && true || (komplexes ding das letztendlich false ergeben würde); // (...) wird nicht mehr ausgewertet
    bool erg2 = (false) || true && true;                                               // (...) wird komplett ausgewertet da sequence point, dann || true, (obwohl da ein lookahead massig sparen könnte :) ) dann && true wieder ausgewertet ?
    bool erg3 = (true)  || false && true;                                              // (...) wird komplett ausgewertet, || false wird verworfen und && true wieder ausgewertet ?
    

    erg1 ist (true && true) || (komplexes ding...) . Bei true && true werden beide Operanden ausgewertet, das Ergebnis ist true. Das ist dann auch der erste Operand des ||, damit muss der rechte Operand nicht mehr ausgewertet werden. Dasselbe bei den anderen vorzuexerzieren spar ich mir jetzt, das ist alles völlig banal.

    Wie siehts aus mit deMorgan ... bastelt der Kompiler da was?

    Davon würde ich ausgehen, das ist ja naheliegend und machbar.



  • Jockelx schrieb:

    padreigh schrieb:

    Nein. Es ist so auch besser da es dem compiler optimierungen erleichtert

    Ob das wirklich 'besser' ist, würde ich so pauschal nicht unterschreiben.
    Ist zumindest eine dicke Stolperfalle für Leute, die es von C# oder Java anders kennen.

    Ich kann mir gerade nix vorstellen wo man drüberstolpern könnte, was nicht gleichzeitig unsauberer Code wäre.

    Kannst du mir ein Beispiel geben?


  • Mod

    hustbaer schrieb:

    Ich kann mir gerade nix vorstellen wo man drüberstolpern könnte, was nicht gleichzeitig unsauberer Code wäre.

    Es sagt ja keiner, dass Java-Programmierer sauber arbeiten 😃

    Kannst du mir ein Beispiel geben?

    int count()
    {
     static int counter=0;
     return ++counter;
    }
    
    cout<<"First count: "<<count()<<" Second count: "<<count();
    

    Sieht auf den ersten Blick nicht gerade unsauber aus (für dich als erfahrenen C++-Programmierer vielleicht doch), aber was wird ausgegeben?


Anmelden zum Antworten