다음 코드는 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;
}
그래서 여기 거래는 다음과 같습니다 오버 플로우가 기술적으로 정의되지 않은 동작입니다 정수를 체결했다. 그러나 x86의 GCC는 x86 정수 명령어를 사용하여 정수 산술을 구현합니다.
따라서 정의되지 않은 동작이라는 사실에도 불구하고 오버플로를 감쌀 것으로 예상했습니다. 그러나 그것은 사실이 아닙니다. 그래서 내가 무엇을 놓쳤습니까?
나는 이것을 사용하여 이것을 컴파일했다 :
~/Desktop$ g++ main.cpp -O2
GCC 출력 :
~/Desktop$ ./a.out
536870912
1073741824
-2147483648
0
0
0
... (infinite loop)
최적화가 비활성화되면 무한 루프가 없으며 출력이 정확합니다. Visual Studio는이를 올바르게 컴파일하고 다음 결과를 제공합니다.
올바른 출력 :
~/Desktop$ g++ main.cpp
~/Desktop$ ./a.out
536870912
1073741824
-2147483648
3
다른 변형은 다음과 같습니다.
i *= 2; // Also fails and goes into infinite loop.
i <<= 1; // This seems okay. It does not enter infinite loop.
모든 관련 버전 정보는 다음과 같습니다.
~/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$
질문은 GCC의 버그입니까? 아니면 GCC가 정수 산술을 처리하는 방법에 대해 잘못 이해 했습니까?
*이 버그가 C로 재생산된다고 가정하기 때문에이 C에도 태그를 지정하고 있습니다 (아직 확인하지 않았습니다).
편집하다:
다음은 루프 어셈블리입니다. (올바르게 인식 한 경우)
.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
.