Unterschiedliches Verhalten des Kommaoperators in C ++ mit Rückgabe?

83

Dies (beachten Sie den Komma-Operator ):

#include <iostream>
int main() {
    int x;
    x = 2, 3;
    std::cout << x << "\n";
    return 0;
}

Ausgänge 2 .

Wenn Sie jedoch returnden Komma-Operator verwenden, gilt Folgendes:

#include <iostream>
int f() { return 2, 3; }
int main() {
    int x;
    x = f();
    std::cout << x << "\n";
    return 0;
}

Ausgänge 3 .

Warum verhält sich der Kommaoperator anders return?

ps95
quelle

Antworten:

139

Nach dem Operator Präzedenz , Komma - Operator hat niedrigere Priorität als operator=, so x = 2,3;entspricht (x = 2),3;. (Die Priorität des Operators bestimmt, wie der Operator an seine Argumente gebunden wird, je nach Priorität enger oder lockerer als andere Operatoren.)

Beachten Sie, dass der Komma-Ausdruck (x = 2),3hier nicht steht 2,3. x = 2wird zuerst ausgewertet (und seine Nebenwirkungen sind abgeschlossen), dann wird das Ergebnis verworfen und dann 3ausgewertet (es tut tatsächlich nichts). Deshalb ist der Wert xist 2. Beachten Sie, dass dies 3das Ergebnis des gesamten Kommaausdrucks ist (dh x = 2,3), für dessen Zuweisung er nicht verwendet wird x. (Ändern Sie es in x = (2,3);, xwird zugewiesen mit 3.)

Für return 2,3;ist das Komma Ausdruck 2,3, 2bewertet wird , dann wird das Ergebnis verworfen und dann 3ausgewertet wird und als das Ergebnis des gesamten Komma Ausdruck zurückgegeben, der durch die zurückgeführt wird return - Anweisung später.


Zusätzliche Informationen zu Ausdrücken und Aussagen

Ein Ausdruck ist eine Folge von Operatoren und ihren Operanden, die eine Berechnung angibt.

x = 2,3;ist Ausdruck Aussage , x = 2,3ist der Ausdruck hier.

Ein Ausdruck gefolgt von einem Semikolon ist eine Aussage.

Syntax: attr(optional) expression(optional) ; (1)

return 2,3;ist die Sprunganweisung ( return-Anweisung ), 2,3ist hier der Ausdruck.

Syntax: attr(optional) return expression(optional) ; (1)

songyuanyao
quelle
1
gute Erklärung. Aber gibt es einige praktische Anwendungen? oder nur Fehler zu machen?
Jean-François Fabre
7
@ Jean-FrançoisFabre IMO es ist nur verwirrend, überhaupt nicht nützlich.
Songyuanyao
11
Ich habe es ein- oder zweimal in forSchleifen gesehen, wenn es seltsamerweise Code in numerischen Berechnungen klarer machen kann.
Bathseba
6
@ Jean-FrançoisFabre: Wie Bathesheba sagt, ist es so, dass Sie so etwas wie i += 1, j += 2in einer for-Schleife schreiben können . Jemand hat entschieden, dass die C ++ - Grammatik (oder besser gesagt die C-Grammatik, da dieser Teil von dort kopiert wurde) bereits kompliziert genug ist, ohne zu definieren, dass die Priorität des Kommas beim Schreiben höher ist als die Zuweisung, beim Schreiben x = 2, 3jedoch niedriger x = 2, y = 3!
Steve Jessop
1
@Holger: Semikolon beendet eine Anweisung, es ist kein Operator. Dies ist etwas, das die Antwort optimieren könnte, um klarer zu machen. "x = 2, 3" ist ein Ausdruck mit 2 Operatoren und hat aus Gründen der Unterstützung für (;;) eine höhere Priorität. (Wie alle anderen sagten.) Aber "kehre 2, 3 zurück;" ist eine Anweisung, die den Ausdruck "2, 3" enthält. Es ist nicht technisch ein Vorrang zu dem Schlüsselwort „Return“. (Obwohl effektiv , da es Teil der Anweisung ist, die den Ausdruck akzeptiert, wird es zuletzt analysiert - niedrigere "Priorität" als jeder Operator im Ausdruck.)
Micha Berger
32

Der Komma- Operator (auch als Ausdruckstrennung bezeichnet ) wird von links nach rechts ausgewertet. Ist return 2,3;also gleichbedeutend mit return 3;.

Die Bewertung von x = 2,3;ist (x = 2), 3;auf die Priorität des Bedieners zurückzuführen . Die Auswertung erfolgt immer noch von links nach rechts, und der gesamte Ausdruck hat den Wert 3 mit dem Nebeneffekt, xdass der Wert 2 angenommen wird.

Bathseba
quelle
2
Können Sie bitte den Ausdruckstrennungsoperator bearbeiten und näher erläutern ? Wie ich in einem Kommentar zu @ songyuanyaos Antwort erwähnt habe, kann ich verstehen, warum return 2,3und return (2,3)sind gleich. Ich glaubte, das erstere sollte sein (return 2),3.
PS95
@BiagioFesta erklärt diesen Teil gut.
Bathseba
1
@ prakharsingh95 return 2ist eine Aussage (wie z. B. die von for,while,if), kein Ausdruck. Du kannst zB f(return 2)oder nicht schreiben 2+return 2. Ist (return 2),3also syntaktisch ungültig.
Chi
@chi Ja, du bist richtig. Ich meinte, ich hätte erwartet return 2, 3, als interpretiert zu werden (return 2), 3.
PS95
2
@ prakharsingh95 kann gemäß der Grammatik von C ++ returnnur in den folgenden Fällen auftreten: (a) return expression_opt ; und (b) return braced-init-list ; .
MM
20

Diese Aussage:

  x = 2,3;

besteht aus zwei Ausdrücken :

> x = 2
> 3

Da Operator Vorrang , =hat mehr Priorität als Komma ,, so x = 2ausgewertet wird und nach 3 . Dann xwird gleich sein 2.


In der returnstattdessen:

int f(){ return 2,3; }

Die Sprachsyntax lautet:

return <expression>

Hinweis return ist nicht Teil des Ausdrucks.

In diesem Fall werden die beiden Ausdrücke wie folgt ausgewertet:

> 2
> 3

Es wird jedoch nur das zweite ( 3) zurückgegeben.

Biagio Festa
quelle
2
UV'd. Sehr wählerisch, aber wäre schön, wenn Sie <expression>(aus grammatikalischer Sicht) als explizit optional markieren würden .
Bathseba
2
Es gibt 5 Ausdrücke im Analysebaum von x=2,3. Beide Literale 2und 3befinden sich am unteren Rand des Analysebaums, ebenso wie der Bezeichner x. Dies sind alles individuell gültige Ausdrücke. Operatorpriorität bedeutet, dass sie im Analysebaum niedriger= auftritt und die beiden Ausdrücke und den vierten Ausdruck kombiniert . Schließlich wird der fünfte Ausdruck durch den Kommaoperator gebildet, der seine beiden Seiten und verbindet . Sie geben jedoch fälschlicherweise an, dass die Priorität des Operators die Reihenfolge der Auswertung bestimmt. Das tut es nicht. Die Reihenfolge der Auswertung wird durch Sequenzierungsregeln bestimmt. x2x=2x=23
MSalters
2
Ich habe dafür gestimmt, dass die Rückkehr nicht Teil eines Ausdrucks ist
Daniel Jour
@ MSalters Ich stimme Ihnen zu, aber ich habe das Wort " weil " anstelle von " seit " falsch verwendet . Etwas mein Englisch ist nicht so perfekt! ; - =
Biagio Festa
2
Ist "Makroausdruck" hier ein Fachbegriff? Es scheint etwas verwirrend, es zu verwenden, wenn auch "Makroausdrücke" im Sinne von Präprozessor-Dingen existieren.
Senshin
2

Versuchen Sie, den simplen Ansatz anzuwenden, indem Sie nur den Vorrang in Klammern hervorheben:

( x = 2 ), 3;

return ( 2, 3 );

Jetzt können wir sehen, dass der binäre Operator "" auf beiden von links nach rechts auf die gleiche Weise funktioniert.

Luciano
quelle
1
Der schwierige Teil ist zu erkennen, dass das x = 2, 3selbst ein Ausdruck ist, während für returnes return <expression>. Also liest du sie als (x = 2, 3)und (2, 3).
PS95