Sentencia de asignación utilizada en operadores condicionales

¿Puede alguien decirme por qué esta statement está dando un error? Lvalue Required

(a>b?g=a:g=b); 

pero este es correcto

 (a>b?g=a:(g=b)); 

donde a , b y g son variables enteras, y a y b se toman como entrada desde el teclado.

En la expresión,

 (a > b ? g = a : g = b); 

el operador relacional > tiene la prioridad más alta, por lo que a > b se agrupa como un operando. ¿El operador de expresión condicional ? : ? : tiene la siguiente prioridad más alta. Su primer operando es a>b , y su segundo operando es g = a . Sin embargo, se considera que el último operando del operador de expresión condicional es g lugar de g = b , ya que esta aparición de g enlaza más estrechamente con el operador de expresión condicional que con el operador de asignación . Se produce un error de syntax porque = b no tiene un operando de la izquierda (valor l).
Debe usar paréntesis para evitar errores de este tipo y generar un código más legible que se haya hecho en su segunda statement.

 (a > b ? g = a : (g = b)); 

en el que el último operando g = b de : ? tiene un valor l g y por eso es correcto.

Alternativamente puedes hacer

 g = a > b ? a : b 

La expresion:

 (a>b?g=a:g=b) 

analizado como

 (a>b?g=a:g)=b 

Y no podemos asignar a una expresión, por lo que es un error de l-valor.

Leer: Diferencias de operadores condicionales entre C y C ++ La respuesta de Charles Bailey:

La gramática para ?: Es la siguiente:

 conditional-expression: logical-OR-expression logical-OR-expression ? expression : conditional-expression 

Esto significa que a ? b : c = d a ? b : c = d analiza como (a ? b : c) = d , aunque (debido a la regla ‘no es un valor de l’) esto no puede dar como resultado una expresión válida.

Una nota al margen :

Por favor, mantenga espacio en su expresión para que sea legible, por ejemplo.

 (a>b?g=a:g=b); 

Debe escribirse como:

 (a > b? g = a: g = b); 

de manera similar, debe agregar espacio después ; y,.

El problema es la precedencia del operador : en C, el operador condicional ternario ( ?: Tiene una precedencia más alta que el operador de asignación ( = ).

Sin paréntesis (que no hace nada aquí) tu expresión sería esta:

 a > b ? g = a : g = b; 

El operador con la mayor prioridad allí sería la comparación > , así que aquí es donde obtendrás tu primera agrupación lógica:

 (a > b) ? g = a : g = b; 

La siguiente expresión más alta es el condicional ternario, que da como resultado la siguiente expresión:

 ((a > b) ? (g = a) : (g)) = b; 

Como puede ver, ahora terminará con un lvalue (es decir, un valor, no una variable) en el lado izquierdo de su operador de asignación, algo que no funcionará.

Como ya notó, la solución a esto es simplemente agrupar las expresiones por su cuenta. Incluso consideraría esta buena práctica, especialmente si no está seguro de cómo podría desempeñarse su precedencia. Si no quiere pensar en ello, agregue paréntesis. Solo tenga en cuenta la legibilidad del código, de modo que, si puede, resuelva la prioridad del operador por su cuenta, para asegurarse de que todo esté correcto y legible.

En cuanto a la legibilidad: probablemente usaría el clásico if() aquí o movería el operador de asignación fuera del condicional ternario, que es como usualmente define max() :

 g = a > b ? a : b; 

O más general como una macro o función en línea:

 #define max(a, b) ((a) > (b) ? (a) : (b)) inline int max(int a, int b) { return a > b ? a : b; } 
 if(a>b) { g = a; } else { g = b; } 

que puede ser reemplazado con esto

 g = a > b ? a : b; //if a>b use the first (a) else use the second (b) 

Su expresión (a>b?g=a:g=b) se analiza como:

 (a>b?g=a:g)=b // ^^^ 

De la documentación de Microsoft :

  conditional-expression: logical-or-expression logical-or-expression ? expression : conditional-expression 

En C, el operador ?: Tiene una prioridad más alta que el operador = . Entonces significa que ( a ? b : c = d ) se analizará como ( a ? b : c ) = d . Debido a la regla de l-value, la primera expresión también es válida pero no está haciendo lo que piensas.

Para evitar este error, puedes hacer también:

 g = ( a > b ) ? a : b; 

Esta pregunta generalmente provoca una avalancha de respuestas que intentan explicar la situación a través del concepto de precedencia del operador . En realidad, no se puede explicar de esa manera, ya que este es un ejemplo típico de una entrada, en el que se desglosan conceptos sustitutivos como “precedencia del operador”. Como usted probablemente sabe, en realidad no hay “precedencia de operadores” en C. Solo hay agrupaciones gtwigticales, que generalmente no se pueden express con precisión a través de un ordenamiento lineal de operadores.

Echemos un vistazo a lo que dice la especificación del lenguaje al respecto. Las partes relevantes de la gramática C en este caso son las gramáticas de ?: Operator y = operator. Para ?: Operador es

 conditional-expression: logical-OR-expression logical-OR-expression ? expression : conditional-expression 

y para el operador = es

 assignment-expression: conditional-expression unary-expression assignment-operator assignment-expression 

En el primer caso, la parte crítica es el último operando de ?: Operator: no es una expression , sino una conditional-expression . La conditional-expression es un punto de entrada diferente en la gramática de la expresión C: “ingresa” a la gramática en el punto donde ya no es posible incluir un operador de nivel superior = en una conditional-expression . La única manera de “contrabandear” un operador = en una conditional-expression es descender la gramática hasta el final

 primary-expression: identifier constant string-literal ( expression ) generic-selection 

y luego envolver todo el camino hasta la parte superior utilizando la twig ( expression ) . Esto significa que una conditional-expression puede contener un operador = solo cuando está explícitamente envuelta en (...) . Por ejemplo, la gramática le prohíbe tener g = b como el último operando de ?: Operator. Si quieres algo como eso, tienes que paréntesis explícito: ? : (g = b) ? : (g = b) .

Una situación muy similar existe con la segunda parte de la gramática: el operador de asignación. El lado izquierdo (LHS) de la asignación es unary-expression . Y unary-expression “ingresa” a la gramática general de la expresión C en el punto en el que es demasiado tarde para incluir un operador de nivel superior ?: La única forma de llegar al operador ?: Desde unary-expression es descender hasta primary-expression y tomar la twig ( expression ) . Esto significa que la gramática te prohíbe tener a > b ? g = a : g a > b ? g = a : g como el operando LHS del operador = . Si quieres algo como eso, tienes que parentelarlo explícitamente: (a > b ? g = a : g) = .

Por esta razón, las respuestas “populares” afirman que la “precedencia del operador” hace que el lenguaje analice su expresión como

 (a > b ? g = a : g) = b 

En realidad son completamente incorrectos. En realidad, no hay ningún árbol de derivación en la gramática C formal que haga que su entrada se ajuste a la syntax del lenguaje C. Su entrada no es analizable en absoluto. No es una expresión. Es simplemente inválido sintácticamente. El lenguaje C lo ve como un gibberish sintáctico.

Ahora, en la práctica, es posible que vea algunas implementaciones para responder con un mensaje de diagnóstico de “lvalor requerido como operando izquierdo de asignación”. Formalmente, este es un mensaje de diagnóstico engañoso. Dado que la entrada anterior no satisface la gramática de la expresión en lenguaje C, no hay “asignación” en ella, no hay “operando izquierdo” y no hay un requisito significativo de “lvalue”.

¿Por qué los comstackdores emiten este extraño mensaje? Lo más probable es que analicen esta entrada como una expresión C válida.

 (a > b ? g = a : g) = b 

El resultado de ?: Nunca es un lvalue en C, de ahí el error. Sin embargo, esta interpretación de su entrada es un comportamiento no estándar (¿extendido?), Que no tiene base en el lenguaje C formal. Este comportamiento de implementaciones específicas puede deberse a sus bashs de conciliar las gramáticas C y C ++ (que son bastante diferentes en esta área), a sus bashs de producir un mensaje de error más legible (aunque sea “falso”) o por algún otro motivo.

Por lo general, en dichas implementaciones, también surgirá un problema similar en el caso de entradas como

 a + b = 5 

Se emitiría el mismo error, sugiriendo un (a + b) = 5 parse, mientras que desde el punto de vista pedante a + b = 5 no se puede analizar como una expresión en absoluto (por las mismas razones descritas anteriormente).

Nuevamente, formalmente, esto no es suficiente para decir que el comstackdor está “roto”: el comstackdor debe detectar una infracción de restricción y emitir algún mensaje de diagnóstico, que es exactamente lo que sucede aquí. El hecho de que el texto del mensaje de diagnóstico no refleje correctamente la naturaleza del problema es intrascendente (el comstackdor simplemente puede decir “¡Ja, ja, ja!”). Pero una consecuencia indeseable de estos diagnósticos engañosos es que engaña a los usuarios para que malinterpreten el problema, lo que es, sin duda, evidente por el aluvión de respuestas formalmente incorrectas publicadas en esta pregunta.