El siguiente código entra en un bucle infinito en GCC:
#include <iostream>
using namespace std;
int main(){
int i = 0x10000000;
int c = 0;
do{
c++;
i += i;
cout << i << endl;
}while (i > 0);
cout << c << endl;
return 0;
}
Así que aquí está el trato: el desbordamiento de entero firmado es un comportamiento técnicamente indefinido. Pero GCC en x86 implementa aritmética de enteros utilizando instrucciones de enteros x86, que se ajustan al desbordamiento.
Por lo tanto, hubiera esperado que se ajustara al desbordamiento, a pesar del hecho de que es un comportamiento indefinido. Pero claramente ese no es el caso. ¿Así que ... qué me perdí?
Compilé esto usando:
~/Desktop$ g++ main.cpp -O2
Salida de GCC:
~/Desktop$ ./a.out
536870912
1073741824
-2147483648
0
0
0
... (infinite loop)
Con las optimizaciones deshabilitadas, no hay un bucle infinito y la salida es correcta. Visual Studio también compila correctamente esto y da el siguiente resultado:
Salida correcta:
~/Desktop$ g++ main.cpp
~/Desktop$ ./a.out
536870912
1073741824
-2147483648
3
Aquí hay algunas otras variaciones:
i *= 2; // Also fails and goes into infinite loop.
i <<= 1; // This seems okay. It does not enter infinite loop.
Aquí está toda la información relevante de la versión:
~/Desktop$ g++ -v
Using built-in specs.
COLLECT_GCC=g++
COLLECT_LTO_WRAPPER=/usr/lib/x86_64-linux-gnu/gcc/x86_64-linux-gnu/4.5.2/lto-wrapper
Target: x86_64-linux-gnu
Configured with: ..
...
Thread model: posix
gcc version 4.5.2 (Ubuntu/Linaro 4.5.2-8ubuntu4)
~/Desktop$
Entonces la pregunta es: ¿Es esto un error en GCC? ¿O entendí mal algo acerca de cómo GCC maneja la aritmética de enteros?
* También etiqueto este C, porque supongo que este error se reproducirá en C. (aún no lo he verificado).
EDITAR:
Aquí está el ensamblaje del bucle: (si lo reconocí correctamente)
.L5:
addl %ebp, %ebp
movl $_ZSt4cout, %edi
movl %ebp, %esi
.cfi_offset 3, -40
call _ZNSolsEi
movq %rax, %rbx
movq (%rax), %rax
movq -24(%rax), %rax
movq 240(%rbx,%rax), %r13
testq %r13, %r13
je .L10
cmpb $0, 56(%r13)
je .L3
movzbl 67(%r13), %eax
.L4:
movsbl %al, %esi
movq %rbx, %rdi
addl $1, %r12d
call _ZNSo3putEc
movq %rax, %rdi
call _ZNSo5flushEv
cmpl $3, %r12d
jne .L5
gcc -S
.