Reihenfolge der Auswertung von Argumenten mit std::cout

Lesezeit: 4 Minuten

Reihenfolge der Auswertung von Argumenten mit stdcout
FehlgeschlagenDev

Hallo zusammen, ich bin heute über diesen Code gestolpert und bin verwirrt, was genau passiert und insbesondere in welcher Reihenfolge:

Code:

#include <iostream>

bool foo(double & m)
{
    m = 1.0;
    return true;
}

int main()
{
    double test = 0.0;
    std::cout << "Value of test is : \t" << test << "\tReturn value of function is : " << foo(test) <<  "\tValue of test : " << test << std::endl;
    return 0;
}

Die Ausgabe ist:

Value of test is :      1       Return value of function is : 1 Value of test : 0

Wenn ich das sehe, würde ich annehmen, dass irgendwie das am weitesten rechts stehende Argument vor dem Aufruf der Funktion ausgegeben wird. Das ist also eine Rechts-Links-Bewertung?? Während des Debuggens scheint es jedoch, dass die Funktion vor der Ausgabe aufgerufen wird, was ich erwarten würde. Ich verwende Win7 und MSVS 2010. Jede Hilfe ist willkommen!

Reihenfolge der Auswertung von Argumenten mit stdcout
Matteo Italien

Die Auswertungsreihenfolge von Elementen in einem Ausdruck ist nicht festgelegt (mit Ausnahme einiger sehr spezieller Fälle, wie z && und || Operatoren und der ternäre Operator, die einführen Sequenzpunkte); das ist also nicht garantiert test wird vorher oder nachher ausgewertet foo(test) (was es modifiziert).

Wenn Ihr Code auf einer bestimmten Auswertungsreihenfolge beruht, ist die einfachste Methode, diese zu erhalten, den Ausdruck in mehrere getrennte Anweisungen aufzuteilen.

  • Kennen Sie einen Trick mit || oder && eine bestimmte Auswertungsreihenfolge durchzusetzen in a << Kette?

    – alfC

    20. Mai 2016 um 23:12 Uhr

  • Nein, aber ich kenne einen Trick ; und die Stream-Variable nach einem Zeilenumbruch wiederholen 😉

    – Matteo Italien

    21. Mai 2016 um 3:25 Uhr

  • Vielleicht wäre das Aktualisieren dieser Antwort mit den im C++17-Standard eingeführten Änderungen hilfreich für Leute, die in Zukunft darauf stoßen: stackoverflow.com/a/50361417/9385966

    – flegar

    16. Mai 2018 um 2:12 Uhr


Die Antwort auf diese Frage hat sich in C++17 geändert.

Die Auswertung überladener Operatoren erfolgt jetzt genauso wie bei integrierten Operatoren (C++17 [over.match.oper]/2).

Außerdem die <<, >> und tiefstellende Operatoren haben jetzt den linken Operanden zuvor sequenziert rechts, und der Postfix-Ausdruck eines Funktionsaufrufs ist zuvor sequenziert Bewertung der Argumente.

(Die anderen binären Operatoren behalten ihre bisherige Reihenfolge bei, z + ist noch nicht sequenziert).

Der Code in der Frage muss also jetzt ausgegeben werden Value of test is : 0 Return value of function is : 1 Value of test : 1. Aber der Rat „Tu das nicht“ ist immer noch vernünftig, da es einige Zeit dauern wird, bis alle auf C++17 aktualisieren.

Die Reihenfolge der Auswertung ist nicht festgelegt. Es ist nicht von links nach rechts, von rechts nach links oder irgendetwas anderes.

Tu das nicht.

1647100207 469 Reihenfolge der Auswertung von Argumenten mit stdcout
Duncan

Die Reihenfolge der Auswertung ist nicht festgelegt, vgl http://en.wikipedia.org/wiki/Sequence_point

Dies ist die gleiche Situation wie im Beispiel mit dem operator+-Beispiel:

Betrachten Sie zwei Funktionen f() und g(). In C und C++ ist die + -Operator ist keinem Sequenzpunkt zugeordnet und daher im Ausdruck enthalten f()+g() das ist auch möglich f() oder g() wird zuerst ausgeführt.

Die C++-Referenz erklärt sehr gut, warum dies niemals getan werden sollte (verursacht ein UB oder ein undefiniertes Verhalten).
https://en.cppreference.com/w/cpp/language/operator_incdec

#include <iostream>

int main()
{
    int n1 = 1;
    int n2 = ++n1;
    int n3 = ++ ++n1;
    int n4 = n1++;
//  int n5 = n1++ ++;   // error
//  int n6 = n1 + ++n1; // undefined behavior
    std::cout << "n1 = " << n1 << '\n'
              << "n2 = " << n2 << '\n'
              << "n3 = " << n3 << '\n'
              << "n4 = " << n4 << '\n';
}

Anmerkungen

Aufgrund der damit verbundenen Nebenwirkungen müssen integrierte Inkrement- und Dekrementoperatoren mit Vorsicht verwendet werden, um undefiniertes Verhalten aufgrund von Verletzungen von Sequenzierungsregeln zu vermeiden.


und im Abschnitt über Sequenzierungsregeln können Sie Folgendes lesen:

Undefiniertes Verhalten:

1) Wenn eine Nebenwirkung auf ein skalares Objekt relativ zu einer anderen Nebenwirkung auf dasselbe skalare Objekt nicht sequenziert ist, ist das Verhalten undefiniert.

i = ++i + 2;       // undefined behavior until C++11
i = i++ + 2;       // undefined behavior until C++17
f(i = -2, i = -2); // undefined behavior until C++17
f(++i, ++i);       // undefined behavior until C++17, unspecified after C++17
i = ++i + i++;     // undefined behavior

2) Wenn ein Nebeneffekt auf ein skalares Objekt relativ zu einer Wertberechnung unter Verwendung des Werts desselben skalaren Objekts nicht sequenziert ist, ist das Verhalten undefiniert.

cout << i << i++; // undefined behavior until C++17
a[i] = i++;       // undefined behavior until C++17
n = ++i + i;      // undefined behavior 

994210cookie-checkReihenfolge der Auswertung von Argumenten mit std::cout

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy