vida reales real paranormales para muy mexico leer historias fuerte famosos experiencias divertidos cosas cortas acertijos c++ puzzle operator-precedence

c++ - muy - historias paranormales reales en mexico



Misterio C++ (9)

¿Puede alguien explicarme por qué este código imprime 14? Me acabo de preguntar otro alumno y no pude entenderlo.

int i = 5; i = ++i + ++i; cout<<i;


Ese es un comportamiento indefinido, el resultado variará según el compilador que use. Ver, por ejemplo, C ++ FAQ Lite .


Porque el incremento del prefijo tiene prioridad:

int i = 5; i = i+1; // First ++i, i is now 6 i = i+1; // Second ++i, i is now 7 i = i + i // i = 7 + 7 cout << i // i = 14


Simple ... el compilador está evaluando AMBOS incrementos antes de realizar la suma, sin almacenar en caché los resultados intermedios. Esto significa que cuando agrega i dos veces, ahora tiene el valor de 7.

Si lo haces

int j=++i; int k=++i; i = j+k;

verá 13 como se esperaba.


i = i++ + i; //11 i = i++ + i++; //12 i = i++ + ++i; //13 i = ++i + i++; //13 i = ++i + ++i; //14


Creo que al ver el problema desde la vista del árbol de sintaxis, la respuesta al problema se vuelve más clara:

yo
|
=
|
+
|
expresión unaria - expresión unaria

expresión unaria: expresión de operador unario

En nuestro caso, la expresión se reduce a la variable i.

Ahora lo que sucede es que ambas expresiones unarias modifican el mismo operando, por lo que el código hace dos veces ++ i al evaluar las expresiones únicas antes de agregar los resultados de ambas expresiones unarias.

Entonces, ¿qué hace el código?

++ i;
++ i;
i = i + i;

Para i = 5 eso significa

i = i + 1; // i <- 6
i = i + 1; // i <- 7
i = i + i; // i <- 14


En algunas de las respuestas / comentarios ha habido una discusión sobre el significado de ''comportamiento indefinido'' y si eso hace que el programa sea inválido. Así que estoy publicando esta respuesta bastante larga que detalla exactamente lo que dice el estándar con algunas notas. Espero que no sea demasiado aburrido ...

Los bits entre comillas del estándar provienen del estándar actual de C ++ (ISO / IEC 14882: 2003). Hay una redacción similar en el estándar C.

Según el estándar de C ++, modificar un valor más de una vez dentro de un conjunto de puntos de secuencia da como resultado un comportamiento indefinido (sección 5, párrafo 4):

Excepto donde se indique, el orden de evaluación de operandos de operadores individuales y subexpresiones de expresiones individuales, y el orden en que se producen los efectos secundarios, no se especifica.53) Entre el punto de secuencia anterior y el siguiente, un objeto escalar tendrá su valor almacenado modificado como máximo una vez por la evaluación de una expresión. Además, se accederá al valor anterior solo para determinar el valor que se almacenará. Los requisitos de este párrafo se cumplirán para cada orden permisible de las subexpresiones de una expresión completa; de lo contrario, el comportamiento no está definido. [Ejemplo:

i = v[i++]; // the behavior is unspecified i = 7, i++, i++; // i becomes 9 i = ++i + 1; // the behavior is unspecified i = i + 1; // the value of i is incremented

-Final ejemplo]

Tenga en cuenta que el segundo ejemplo, " i = 7, i++, i++; " se define porque el operador de coma es un punto de secuencia.

Esto es lo que el estándar de C ++ dice ''comportamiento indefinido'' significa:

1.3.12 comportamiento indefinido [defns.undefined]

comportamiento, tal como podría surgir al usar una construcción de programa errónea o datos erróneos, para los cuales esta Norma Internacional no impone requisitos. También se puede esperar un comportamiento indefinido cuando esta Norma Internacional omite la descripción de cualquier definición explícita de comportamiento. [Nota: el comportamiento permisible indefinido va desde ignorar la situación completamente con resultados impredecibles, hasta comportarse durante la traducción o ejecución del programa de una manera documentada característica del entorno (con o sin la emisión de un mensaje de diagnóstico), hasta terminar una traducción o ejecución ( con la emisión de un mensaje de diagnóstico). Muchos constructos erróneos del programa no engendran un comportamiento indefinido; se requiere que sean diagnosticados. ]

En otras palabras, el compilador es libre de hacer lo que quiera, incluyendo

  1. escupiendo un mensaje de error,
  2. haciendo algo implementación definida y documentada,
  3. tener resultados completamente impredecibles

El segundo elemento cubre las extensiones de lenguaje que tienen la mayoría de los compiladores, pero por supuesto no están definidos en el estándar.

Así que supongo que, estrictamente hablando, algo que muestra un comportamiento indefinido no es "ilegal", pero en mi experiencia siempre que haya algo en un programa C / C ++ que muestre un "comportamiento indefinido" (a menos que sea una extensión), es un error. Creo que llamar ilegal a tal construcción no es confuso, engañoso o equivocado.

Además, creo que tratar de explicar qué está haciendo el compilador para alcanzar el valor 14 no es particularmente útil, ya que eso no tiene sentido. El compilador podría estar haciendo casi cualquier cosa; de hecho, es probable que el compilador pueda alcanzar un resultado diferente cuando se ejecuta usando diferentes opciones de optimización (o puede producir código que se cuelga, ¿quién sabe?).

Para aquellos que desean referencias adicionales o una apelación a la autoridad, estos son algunos consejos:

Steve Summit (mantenedor de las preguntas frecuentes comp.lang.c), larga, larga respuesta sobre este tema desde 1995:

Esto es lo que Bjarne Stroustrup tiene que decir al respecto:

Nota al pie : el estándar de C ++ usa la palabra "ilegal" exactamente una vez, cuando describe una diferencia entre C ++ y el Estándar C con respecto al uso de declaraciones static o extern con tipo.


En su compilador particular, elige hacer ambas operaciones ++ primero, luego la suma. Está interpretando el código como:

int i = 5; ++i; ++i; i = i + i; cout << i;

Eso es perfectamente válido.


Una mejor pregunta sería, ¿siempre será 14 ?

int i = 5; i = ++i + ++i; cout<<i; i = ++i + ++i ; i = ++(5) + ++(5) ; i = 6 + 6 ; i = 12; i = ++i + ++i ; i = ++i + ++(5) ; i = ++i + (6) ; i = ++(6) + 6 ; i = (7) + 6 ; i = 13; i = ++i + ++i ; i = ++i + ++(5) ; i = ++(6) + (6) ; i = (7) + (7) ; i = 14;

Con toda probabilidad, será probablemente 14 , porque tiene un poco más de sentido.


El orden de los efectos secundarios no está definido en C ++. Además, la modificación de una variable dos veces en una sola expresión no tiene un comportamiento definido (consulte el estándar de C ++ , §5.0.4, página física 87 / página lógica 73).

Solución: No use efectos secundarios en expresiones complejas, no use más de uno en expresiones simples. Y no hace daño habilitar todas las advertencias que el compilador puede darle: Agregar -Wall (gcc) o /Wall /W4 (Visual C ++) a la línea de comando produce una advertencia de ajuste:

test-so-side-effects.c: In function ''main'': test-so-side-effects.c:5: warning: operation on ''i'' may be undefined test-so-side-effects.c:5: warning: operation on ''i'' may be undefined

Obviamente, el código se compila para:

i = i + 1; i = i + 1; i = i + i;