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 forbucle no termina en 300? Además, este programa siempre termina en 4169. ¿Por qué 4169y 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
imayor que 173 causaría UB, y debido a que puede asumir que no hay UB, también puede asumir queinunca es mayor que 173. Luego puede probar quei < 300siempre 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
isuperior 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 * 12345678se desborda y da como resultado UB ifi > 173(asumiendo 32 bitsint).inunca se puede exceder173.i < 300lo 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^16caracteres.Está invocando un comportamiento indefinido probablemente en la 174a iteración dentro de su
forbucle, ya que elintvalor máximo probablemente2147483647todavía se174 * 123456789evalúa como una expresión2148147972que 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
-O2indicadores 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 < 300y por lo tanto eliminar la comprobacióni < 300.fuente