punched punch español cards card c lvalue

cards - punch card español



¿Por qué no funciona un+++++ b? (8)

int main () { int a = 5,b = 2; printf("%d",a+++++b); return 0; }

Este código da el siguiente error:

error: lvalue requerido como operando de incremento

Pero si pongo espacios a lo largo de a++ + y ++b , entonces funciona bien.

int main () { int a = 5,b = 2; printf("%d",a++ + ++b); return 0; }

¿Qué significa el error en el primer ejemplo?


Creo que el compilador lo ve como

c = ((a ++) ++) + b

++ tiene que tener como operando un valor que puede ser modificado. a es un valor que puede ser modificado. a++ sin embargo, es un ''rvalue'', no puede ser modificado.

Por cierto, el error que veo en GCC C es el mismo, pero con una redacción diferente: lvalue required as increment operand .


El lexer usa lo que generalmente se llama un algoritmo "máximo munch" para crear tokens. Eso significa que mientras lee caracteres, sigue leyendo caracteres hasta que encuentra algo que no puede formar parte del mismo símbolo que lo que ya tiene (por ejemplo, si ha estado leyendo dígitos, entonces lo que tiene es un número, si encuentra una A , sabe que no puede ser parte del número, por lo que se detiene y deja la A en el búfer de entrada para usarla como el comienzo del siguiente token). Luego devuelve ese token al analizador.

En este caso, eso significa que +++++ se lee como a ++ ++ + b . Dado que el primer incremento posterior arroja un valor r, el segundo no se puede aplicar a él, y el compilador da un error.

Solo FWIW, en C ++ puedes sobrecargar al operator++ para generar un lvalue, que permite que esto funcione. Por ejemplo:

struct bad_code { bad_code &operator++(int) { return *this; } int operator+(bad_code const &other) { return 1; } }; int main() { bad_code a, b; int c = a+++++b; return 0; }

Las compilaciones y ejecuciones (aunque no hace nada) con los compiladores de C ++ que tengo a mano (VC ++, g ++, Comeau).


Este ejemplo exacto está cubierto en el borrador del estándar C99 ( mismos detalles en C11 ) sección 6.4 Elementos léxicos que en el párrafo 4 dice:

Si el flujo de entrada se ha analizado en tokens de preprocesamiento hasta un carácter dado, el siguiente token de preprocesamiento es la secuencia más larga de caracteres que podría constituir un token de preproceso. [...]

que también se conoce como la regla de Munch máxima que se utiliza en el análisis léxico para evitar ambigüedades y funciona tomando tantos elementos como sea posible para formar un token válido.

el párrafo también tiene dos ejemplos, el segundo es una coincidencia exacta para su pregunta y es el siguiente:

EJEMPLO 2 El fragmento de programa x +++++ y se analiza como x ++ ++ + y, lo que infringe una restricción en los operadores de incremento, aunque el análisis x ++ + ++ y podría arrojar una expresión correcta.

que nos dice que:

a+++++b

será analizado como:

a ++ ++ + b

que viola las restricciones en el incremento de puesto ya que el resultado del primer incremento de puesto es un valor r y el incremento posterior requiere un valor l. Esto se trata en la sección 6.5.2.4 Operadores de incremento y disminución de Postfix que dice ( énfasis mío ):

El operando del operador de incremento o disminución de sufijo debe tener un tipo real o puntero calificado o no calificado y debe ser un valor l modificable.

y

El resultado del operador postfix ++ es el valor del operando.

El libro C ++ Gotchas también cubre este caso en Gotcha #17 Maximal Munch Problems, también es el mismo problema en C ++ y también da algunos ejemplos. Explica que cuando se trata del siguiente conjunto de caracteres:

->*

el analizador léxico puede hacer una de tres cosas:

  • Trátelo como tres fichas: - , > y *
  • Trátelo como dos tokens: -> y *
  • Trátelo como una ficha: ->*

La regla máxima de Munch le permite evitar estas ambigüedades. El autor lo señala ( en el contexto de C ++ ):

resuelve muchos más problemas de los que causa, pero en dos situaciones comunes, es una molestia.

El primer ejemplo serían las plantillas cuyos argumentos de plantilla también son plantillas ( que se resolvió en C ++ 11 ), por ejemplo:

list<vector<string>> lovos; // error! ^^

Que interpreta los corchetes angulares de cierre como el operador de desplazamiento , por lo que se requiere un espacio para desambiguar:

list< vector<string> > lovos; ^

El segundo caso implica argumentos predeterminados para los punteros, por ejemplo:

void process( const char *= 0 ); // error! ^^

se interpretaría como *= operador de asignación, la solución en este caso es nombrar los parámetros en la declaración.


Los compiladores se escriben en etapas. La primera etapa se llama lexer y convierte los personajes en una estructura simbólica. Entonces "++" se convierte en algo así como una enum SYMBOL_PLUSPLUS . Más tarde, la etapa de analizador convierte esto en un árbol sintáctico abstracto, pero no puede cambiar los símbolos. Puede afectar al lexer insertando espacios (que terminan con los símbolos a menos que estén entre comillas).

Los lexers normales son codiciosos (con algunas excepciones), por lo que su código se interpreta como

a++ ++ +b

La entrada al analizador es una secuencia de símbolos, por lo que su código sería algo así como:

[ SYMBOL_NAME(name = "a"), SYMBOL_PLUS_PLUS, SYMBOL_PLUS_PLUS, SYMBOL_PLUS, SYMBOL_NAME(name = "b") ]

Que el analizador cree que es sintácticamente incorrecto. (EDIT basado en comentarios: semánticamente incorrecto porque no puede aplicar ++ a un valor r, lo que resulta en a ++)

a+++b

es

a++ +b

Lo cual está bien. También lo son tus otros ejemplos.


Su compilador intenta desesperadamente analizar a+++++b , y lo interpreta como (a++)++ +b . Ahora, el resultado del incremento posterior ( a++ ) no es un valor lvalue , es decir, no se puede incrementar de forma posterior.

Por favor, nunca escriba este código en programas de calidad de producción. Piensa en el pobre tipo que vendrá después de ti y que necesita interpretar tu código.


printf("%d",a+++++b); se interpreta como (a++)++ + b acuerdo con la regla de Munch máxima ! .

++ (postfix) no evalúa a un valor lvalue pero requiere que su operando sea un valor lvalue .

! 6.4 / 4 dice que el siguiente token de preprocesamiento es la secuencia más larga de caracteres que podría constituir un token de preprocesamiento "


Porque causa un comportamiento indefinido.

¿Cuál es?

c = (a++)++ + b c = (a) + ++(++b) c = (a++) + (++b)

Sí, ni tú ni el compilador lo saben.

EDITAR:

La verdadera razón es la que dicen los otros:

Se interpreta como (a++)++ + b .

pero el incremento posterior requiere un lvalue (que es una variable con un nombre) pero (a ++) devuelve un valor r que no puede incrementarse, lo que lleva al mensaje de error que recibe.

Gracias a los demás por señalar esto.


(a++)++ +b

a ++ devuelve el valor anterior, un valor r. No puedes incrementar esto.