Me he encontrado con el siguiente programa C ++ ( fuente ):
#include <iostream>
int main()
{
for (int i = 0; i < 300; i++)
std::cout << i << " " << i * 12345678 << std::endl;
}
Parece un programa simple y da la salida correcta en mi máquina local, es decir, algo como:
0 0
1 12345678
2 24691356
...
297 -628300930
298 -615955252
299 -603609574
Pero, en IDE en línea como codechef , da el siguiente resultado:
0 0
1 12345678
2 24691356
...
4167 -95167326
4168 -82821648
4169 -7047597
¿Por qué el for
bucle no termina en 300? Además, este programa siempre termina en 4169
. ¿Por qué 4169
y no algún otro valor?
c++
undefined-behavior
integer-overflow
arpanmangal
fuente
fuente
Respuestas:
Voy a asumir que los compiladores en línea usan GCC o un compilador compatible. Por supuesto, cualquier otro compilador también puede hacer la misma optimización, pero la documentación de GCC explica bien lo que hace:
Esta opción simplemente permite hacer suposiciones en base a los casos en los que se comprueba la UB. Para aprovechar esas suposiciones, es posible que sea necesario habilitar otras optimizaciones, como el plegado constante.
El desbordamiento de enteros con signo tiene un comportamiento indefinido. El optimizador pudo demostrar que cualquier valor
i
mayor que 173 causaría UB, y debido a que puede asumir que no hay UB, también puede asumir quei
nunca es mayor que 173. Luego puede probar quei < 300
siempre es cierto, y por lo que la condición del bucle se puede optimizar.Esos sitios probablemente limitan el número de líneas de salida (o caracteres o bytes) que muestran y comparten el mismo límite.
fuente
i
superior a 173, ¿por qué no emite una advertencia en lugar de realizar una optimización sin sentido?"El comportamiento indefinido no está definido". (C)
Un compilador usado en codechef parece usar la siguiente lógica:
i * 12345678
se desborda y da como resultado UB ifi > 173
(asumiendo 32 bitsint
).i
nunca se puede exceder173
.i < 300
lo tanto, es superfluo y se puede reemplazar portrue
.El bucle en sí parece infinito. Aparentemente, codechef simplemente detiene el programa después de un período de tiempo específico o trunca la salida.
fuente
2^16
. Aparentemente, es una coincidencia que ambos trunquen la salida a los2^16
caracteres.Está invocando un comportamiento indefinido probablemente en la 174a iteración dentro de su
for
bucle, ya que elint
valor máximo probablemente2147483647
todavía se174 * 123456789
evalúa como una expresión2148147972
que es un comportamiento indefinido, ya que no hay un desbordamiento de enteros con signo. Entonces, está observando los efectos de UB, particularmente con el compilador GCC con indicadores de optimización establecidos en su caso. Es probable que el compilador le haya advertido sobre esto emitiendo la siguiente advertencia:warning: iteration 174 invokes undefined behavior [-Waggressive-loop-optimizations]
Elimine los
-O2
indicadores de optimización ( ) para observar diferentes resultados.fuente
El compilador puede asumir que no se producirá un comportamiento indefinido, y dado que el desbordamiento firmado es UB, puede asumir que nunca
i * 12345678 > INT_MAX
, por lo tanto, tambiéni <= INT_MAX / 12345678 < 300
y por lo tanto eliminar la comprobacióni < 300
.fuente