¿Diferente comportamiento del operador de coma en C ++ con retorno?

83

Esto (tenga en cuenta el operador de coma ):

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

salidas 2 .

Sin embargo, si usa returncon el operador de coma, esto:

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

salidas 3 .

¿Por qué el operador de coma se comporta de manera diferente con return?

xyz
fuente

Respuestas:

140

Según la precedencia del operador , el operador coma tiene una precedencia menor que operator=, por lo que x = 2,3;es equivalente a (x = 2),3;. (La precedencia del operador determina cómo se vinculará el operador a sus argumentos, más estrictos o más flexibles que otros operadores según sus precedentes).

Tenga en cuenta que la expresión de coma está (x = 2),3aquí, no 2,3. x = 2se evalúa al principio (y se completan sus efectos secundarios), luego se descarta el resultado, luego 3se evalúa (no hace nada de hecho). Por eso el valor de xes 2. Tenga en cuenta que 3es el resultado de toda la expresión de coma (es decir x = 2,3), no se utilizará para asignar x. (Cámbielo a x = (2,3);, xse le asignará con 3).

Para return 2,3;la expresión coma es 2,3, 2se evalúa entonces su resultado se descarta, y luego 3se evalúa y se devuelve como el resultado de toda la expresión de coma, que es devuelto por la instrucción de retorno más tarde.


Información adicional sobre Expresiones y declaraciones

Una expresión es una secuencia de operadores y sus operandos, que especifica un cálculo.

x = 2,3;es una declaración de expresión ,x = 2,3 es la expresión aquí.

Una expresión seguida de un punto y coma es una declaración.

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

return 2,3;es la declaración de salto ( declaración de retorno ), 2,3es la expresión aquí.

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

Songyuanyao
fuente
1
buena explicación. ¿Pero existen algunas aplicaciones prácticas? ¿O simplemente errores por hacer?
Jean-François Fabre
7
@ Jean-FrançoisFabre En mi opinión, es confuso, no es útil en absoluto.
Songyuanyao
11
Lo he visto una o dos veces usado en forbucles cuando, extrañamente, puede hacer que el código sea más claro en cálculos numéricos.
Betsabé
6
@ Jean-FrançoisFabre: como dice Bathesheba, es para que puedas escribir algo como i += 1, j += 2en un bucle for. Alguien decidió que la gramática de C ++ (o más bien la gramática de C, ya que esta parte se copió de allí) ya es lo suficientemente complicada sin intentar definir que la precedencia de la coma es más alta que la asignación cuando escribe, ¡ x = 2, 3pero más baja cuando escribe x = 2, y = 3!
Steve Jessop
1
@Holger: punto y coma termina una declaración, no es un operador. Esto es algo que la respuesta podría modificarse para dejar más claro. "x = 2, 3" es una expresión con 2 operadores, y por razones de soporte para (;;), = tiene mayor prioridad. (Como todos los demás dijeron.) Pero "devuelve 2, 3;" es una declaración que contiene la expresión "2, 3". Técnicamente, no existe una precedencia para la palabra clave "retorno". (Aunque efectivamente , dado que es parte de la declaración que acepta la expresión, se analiza en último lugar: "precedencia" más baja que cualquier operador en la expresión.)
Micha Berger
32

El operador de coma (también conocido como separación de expresión ) se evalúa de izquierda a derecha. Entonces return 2,3;es equivalente areturn 3; .

La evaluación de x = 2,3;se (x = 2), 3;debe a la precedencia del operador . La evaluación sigue siendo de izquierda a derecha y toda la expresión tiene el valor 3 con el efecto secundario de xasumir el valor 2.

Betsabé
fuente
2
¿Puede editar y desarrollar más sobre el operador de separación de expresiones ? Como mencioné en un comentario sobre la respuesta de @ songyuanyao, puedo entender por qué return 2,3y return (2,3)son iguales. Creí que lo primero debería ser (return 2),3.
xyz
@BiagioFesta explica bien esa parte.
Betsabé
1
@ prakharsingh95 return 2es una declaración (como por ejemplo, las formadas por for,while,if), no una expresión. No se puede escribir, por ejemplo, f(return 2)o 2+return 2. Entonces, (return 2),3es sintácticamente inválido.
chi
@chi Sí, tienes razón. Quise decir que esperaba return 2, 3ser interpretado como (return 2), 3.
xyz
2
@ prakharsingh95 según la gramática de C ++, returnsolo puede ocurrir en los siguientes casos: (a) return expression_opt ; , y (b) return braced-init-list ; .
MM
20

Esta declaración:

  x = 2,3;

está compuesto por dos expresiones :

> x = 2
> 3

Dado que la precedencia del operador , =tiene más precedencia que la coma ,, por lo que x = 2se evalúa y después 3 . Entonces xserá igual a 2.


En el returnlugar:

int f(){ return 2,3; }

La sintaxis del idioma es:

return <expression>

La nota return no es parte de la expresión.

Entonces, en ese caso, las dos expresiones que se evaluarán serán:

> 2
> 3

Pero solo 3se devolverá el segundo ( ).

Biagio Festa
fuente
2
UV'd. Muy exigente, pero sería bueno si lo marcara <expression>como explícitamente opcional (desde una perspectiva gramatical).
Betsabé
2
Hay 5 expresiones en el árbol de análisis sintáctico de x=2,3. Ambos literales 2y 3están en la parte inferior del árbol de análisis, al igual que el identificador x. Todas estas son expresiones válidas individualmente. Medios de prioridad de operadores que =se produce menor en el árbol de análisis, y combina las dos expresiones xy 2en el cuarto de expresión x=2. Finalmente, la quinta expresión está formada por el operador de coma que une sus dos lados x=2y 3. Sin embargo, afirma incorrectamente que la precedencia de los operadores determina el orden de evaluación. No es así. El orden de evaluación se determina mediante reglas de secuenciación.
MSalters
2
Voté a favor de mencionar que el retorno no es parte de una expresión
Daniel Jour
@MSalters Estoy de acuerdo contigo, pero utilicé incorrectamente la palabra " porque ", en lugar de " desde ". ¡Algo que mi inglés no es tan perfecto! ; - =
Biagio Festa
2
¿Es "macroexpresión" un término técnico aquí? Parece un poco confuso usarlo cuando también existen "macroexpresiones" en el sentido de cosas de preprocesador.
senshin
2

Intente aplicar el enfoque simplista resaltando la precedencia entre paréntesis:

( x = 2 ), 3;

return ( 2, 3 );

Ahora podemos ver el operador binario "," trabajando de la misma manera en ambos, de izquierda a derecha.

Luciano
fuente
1
La parte complicada es darse cuenta de que el x = 2, 3es en sí mismo una expresión, mientras que para returnlo es return <expression>. Entonces los lees como (x = 2, 3)y (2, 3).
xyz