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 en todas partes 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?
x+++++y
se analiza comox ++ ++ + y
, lo que viola una restricción sobre los operadores de incremento, aunque el análisisx ++ + ++ y
podría producir una expresión correcta".Respuestas:
printf("%d",a+++++b);
se interpreta de(a++)++ + b
acuerdo con la Regla de Máximo Munch ! .++
(sufijo) no se evalúa como an,lvalue
pero requiere que su operando sea unlvalue
.! 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 "
fuente
Los compiladores se escriben en etapas. La primera etapa se llama lexer y convierte a los personajes en una estructura simbólica. Entonces "++" se convierte en algo así como un
enum SYMBOL_PLUSPLUS
. Más tarde, la etapa del analizador lo convierte en un árbol de sintaxis abstracto, pero no puede cambiar los símbolos. Puede afectar al lexer insertando espacios (cuyos símbolos finales a menos que estén entre comillas).Los lexers normales son codiciosos (con algunas excepciones), por lo que su código se interpreta como
La entrada al analizador es un flujo de símbolos, por lo que su código sería algo como:
Lo que el analizador piensa que es sintácticamente incorrecto. (EDITAR basado en comentarios: semánticamente incorrecto porque no puede aplicar ++ a un valor r, lo que resulta en un ++)
es
Que esta bien. También lo son sus otros ejemplos.
fuente
a++
).a++
da como resultado un valor r.x = 10&987&&654&&321
es ilegal, pero extrañamentex = 10&987&&654&&&321
es legal.El lexer usa lo que generalmente se llama un algoritmo de "masticación máxima" para crear tokens. Eso significa que mientras lee caracteres, sigue leyendo caracteres hasta que encuentra algo que no puede ser parte del mismo token que el que ya tiene (por ejemplo, si ha estado leyendo dígitos, entonces lo que tiene es un número, si encuentra an
A
, sabe que no puede ser parte del número, por lo que se detiene y dejaA
en el búfer de entrada para usarlo como el comienzo del siguiente token). Luego devuelve ese token al analizador.En este caso, eso significa que
+++++
se lexiza comoa ++ ++ + b
. Dado que el primer incremento posterior produce un rvalue, el segundo no se puede aplicar y el compilador da un error.Solo FWIW, en C ++ puede sobrecargar
operator++
para producir un lvalue, lo que permite que esto funcione. Por ejemplo:Se compila y se ejecuta (aunque no hace nada) con los compiladores de C ++ que tengo a mano (VC ++, g ++, Comeau).
fuente
16FA
es un número hexadecimal perfectamente0x
al principio, lo tratará como16
seguido deFA
, ni un solo número hexadecimal.0x
formaba parte del número.x
un dígito, parecía bastante innecesario.Este ejemplo exacto está cubierto en el borrador de la norma C99 (los mismos detalles en C11 ) sección 6.4 Elementos léxicos párrafo 4 que dice:
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 coincide exactamente con su pregunta y es el siguiente:
que nos dice que:
se analizará como:
lo que viola las restricciones sobre el incremento posterior, ya que el resultado del primer incremento posterior es un valor r y el incremento posterior requiere un valor l. Esto se cubre en la sección
6.5.2.4
Operadores de incremento y decremento de Postfix que dice ( énfasis mío ):y
El libro C ++ Gotchas también cubre este caso en
Gotcha #17
Maximal Munch Problems , es el mismo problema en C ++ y también da algunos ejemplos. Explica eso cuando se trata del siguiente conjunto de caracteres:el analizador léxico puede hacer una de estas tres cosas:
-
,>
y*
->
y*
->*
La regla de munch máximo le permite evitar estas ambigüedades. El autor señala que ( en el contexto de C ++ ):
El primer ejemplo serían plantillas cuyos argumentos de plantilla también son plantillas ( que se resolvió en C ++ 11 ), por ejemplo:
Lo que interpreta los corchetes angulares de cierre como el operador de cambio , por lo que se requiere un espacio para eliminar la ambigüedad:
El segundo caso involucra argumentos predeterminados para punteros, por ejemplo:
se interpretaría como
*=
operador de asignación, la solución en este caso es nombrar los parámetros en la declaración.fuente
>>
regla se solicita en: stackoverflow.com/questions/15785496/…Su compilador intenta desesperadamente analizar
a+++++b
y lo interpreta como(a++)++ +b
. Ahora, el resultado del post-incremento (a++
) no es un valor l , es decir, no se puede volver a incrementar posteriormente.Por favor, nunca escriba ese código en programas de calidad de producción. Piense en el pobre tipo que viene detrás de usted y necesita interpretar su código.
fuente
a ++ devuelve el valor anterior, un rvalue. No puedes incrementar esto.
fuente
Porque provoca un comportamiento indefinido.¿Cuál es?
Sí, ni usted ni el compilador lo saben.EDITAR:
La verdadera razón es la que dijeron los demás:
Se interpreta como
(a++)++ + b
.pero el incremento posterior requiere un lvalue (que es una variable con un nombre) pero (a ++) devuelve un rvalue que no se puede incrementar, lo que lleva al mensaje de error que aparece.
Gracias a los demás por señalar esto.
fuente
a+++b
lo que siempre lo esa++ + b
a++ ++ +b
que no se puede analizar.a+++++b
no evaluar a(a++)++)+b
. Ciertamente, con GCC, si inserta esos corchetes y reconstruye, el mensaje de error no cambia.Creo que el compilador lo ve como
c = ((a ++) ++) + b
++
debe tener como operando un valor modificable. a es un valor que se puede modificar.a++
sin embargo, es un 'rvalue', no se puede modificar.Por cierto, el error que veo en GCC C es el mismo, pero de manera diferente redactada-:
lvalue required as increment operand
.fuente
Siga este orden de precedencia
1. ++ (incremento previo)
2. + - (suma o resta)
3. "x" + "y" suman la secuencia
int a = 5,b = 2; printf("%d",a++ + ++b); //a is 5 since it is post increment b is 3 pre increment return 0; //it is 5+3=8
fuente