İmzalı tamsayı taşması (açık konuşmak gerekirse, "imzasız tamsayı taşması" diye bir şey yoktur) tanımsız davranış anlamına gelir . Ve bu her şeyin olabileceği anlamına gelir ve bunun neden C ++ kuralları altında gerçekleştiğini tartışmak mantıklı değildir.
C ++ 11 taslak N3337: §5.4: 1
Bir ifadenin değerlendirilmesi sırasında, sonuç matematiksel olarak tanımlanmamışsa veya türü için temsil edilebilir değerler aralığında değilse, davranış tanımlanmamıştır. [Not: mevcut C ++ uygulamalarının çoğu tamsayılar üzerinde tamsayıyı yok sayar. Bölmenin sıfıra muamele edilmesi, sıfır bölen kullanılarak bir kalanın oluşturulması ve tüm kaplama noktası istisnaları makineler arasında değişiklik gösterir ve genellikle bir kütüphane işlevi ile ayarlanabilir. —End not]
Kodunuz derlendi g++ -O3
uyarı veriyor (olmadan bile -Wall
)
a.cpp: In function 'int main()':
a.cpp:11:18: warning: iteration 3u invokes undefined behavior [-Waggressive-loop-optimizations]
std::cout << i*1000000000 << std::endl;
^
a.cpp:9:2: note: containing loop
for (int i = 0; i < 4; ++i)
^
Programın ne yaptığını analiz etmenin tek yolu, oluşturulan derleme kodunu okumaktır.
İşte tam montaj listesi:
.file "a.cpp"
.section .text$_ZNKSt5ctypeIcE8do_widenEc,"x"
.linkonce discard
.align 2
LCOLDB0:
LHOTB0:
.align 2
.p2align 4,,15
.globl __ZNKSt5ctypeIcE8do_widenEc
.def __ZNKSt5ctypeIcE8do_widenEc; .scl 2; .type 32; .endef
__ZNKSt5ctypeIcE8do_widenEc:
LFB860:
.cfi_startproc
movzbl 4(%esp), %eax
ret $4
.cfi_endproc
LFE860:
LCOLDE0:
LHOTE0:
.section .text.unlikely,"x"
LCOLDB1:
.text
LHOTB1:
.p2align 4,,15
.def ___tcf_0; .scl 3; .type 32; .endef
___tcf_0:
LFB1091:
.cfi_startproc
movl $__ZStL8__ioinit, %ecx
jmp __ZNSt8ios_base4InitD1Ev
.cfi_endproc
LFE1091:
.section .text.unlikely,"x"
LCOLDE1:
.text
LHOTE1:
.def ___main; .scl 2; .type 32; .endef
.section .text.unlikely,"x"
LCOLDB2:
.section .text.startup,"x"
LHOTB2:
.p2align 4,,15
.globl _main
.def _main; .scl 2; .type 32; .endef
_main:
LFB1084:
.cfi_startproc
leal 4(%esp), %ecx
.cfi_def_cfa 1, 0
andl $-16, %esp
pushl -4(%ecx)
pushl %ebp
.cfi_escape 0x10,0x5,0x2,0x75,0
movl %esp, %ebp
pushl %edi
pushl %esi
pushl %ebx
pushl %ecx
.cfi_escape 0xf,0x3,0x75,0x70,0x6
.cfi_escape 0x10,0x7,0x2,0x75,0x7c
.cfi_escape 0x10,0x6,0x2,0x75,0x78
.cfi_escape 0x10,0x3,0x2,0x75,0x74
xorl %edi, %edi
subl $24, %esp
call ___main
L4:
movl %edi, (%esp)
movl $__ZSt4cout, %ecx
call __ZNSolsEi
movl %eax, %esi
movl (%eax), %eax
subl $4, %esp
movl -12(%eax), %eax
movl 124(%esi,%eax), %ebx
testl %ebx, %ebx
je L15
cmpb $0, 28(%ebx)
je L5
movsbl 39(%ebx), %eax
L6:
movl %esi, %ecx
movl %eax, (%esp)
addl $1000000000, %edi
call __ZNSo3putEc
subl $4, %esp
movl %eax, %ecx
call __ZNSo5flushEv
jmp L4
.p2align 4,,10
L5:
movl %ebx, %ecx
call __ZNKSt5ctypeIcE13_M_widen_initEv
movl (%ebx), %eax
movl 24(%eax), %edx
movl $10, %eax
cmpl $__ZNKSt5ctypeIcE8do_widenEc, %edx
je L6
movl $10, (%esp)
movl %ebx, %ecx
call *%edx
movsbl %al, %eax
pushl %edx
jmp L6
L15:
call __ZSt16__throw_bad_castv
.cfi_endproc
LFE1084:
.section .text.unlikely,"x"
LCOLDE2:
.section .text.startup,"x"
LHOTE2:
.section .text.unlikely,"x"
LCOLDB3:
.section .text.startup,"x"
LHOTB3:
.p2align 4,,15
.def __GLOBAL__sub_I_main; .scl 3; .type 32; .endef
__GLOBAL__sub_I_main:
LFB1092:
.cfi_startproc
subl $28, %esp
.cfi_def_cfa_offset 32
movl $__ZStL8__ioinit, %ecx
call __ZNSt8ios_base4InitC1Ev
movl $___tcf_0, (%esp)
call _atexit
addl $28, %esp
.cfi_def_cfa_offset 4
ret
.cfi_endproc
LFE1092:
.section .text.unlikely,"x"
LCOLDE3:
.section .text.startup,"x"
LHOTE3:
.section .ctors,"w"
.align 4
.long __GLOBAL__sub_I_main
.lcomm __ZStL8__ioinit,1,1
.ident "GCC: (i686-posix-dwarf-rev1, Built by MinGW-W64 project) 4.9.0"
.def __ZNSt8ios_base4InitD1Ev; .scl 2; .type 32; .endef
.def __ZNSolsEi; .scl 2; .type 32; .endef
.def __ZNSo3putEc; .scl 2; .type 32; .endef
.def __ZNSo5flushEv; .scl 2; .type 32; .endef
.def __ZNKSt5ctypeIcE13_M_widen_initEv; .scl 2; .type 32; .endef
.def __ZSt16__throw_bad_castv; .scl 2; .type 32; .endef
.def __ZNSt8ios_base4InitC1Ev; .scl 2; .type 32; .endef
.def _atexit; .scl 2; .type 32; .endef
Meclisi bile okuyamıyorum, hatta hatta görebiliyorum addl $1000000000, %edi
. Ortaya çıkan kod daha çok benziyor
for(int i = 0; /* nothing, that is - infinite loop */; i += 1000000000)
std::cout << i << std::endl;
@TC'nin bu yorumu:
Bunun gibi bir şey olduğundan şüpheleniyorum: (1) i
2'den büyük herhangi bir değere sahip her yineleme tanımlanmamış davranışa sahip olduğundan -> (2) i <= 2
optimizasyon amacıyla -> (3) döngü koşulunun her zaman doğru olduğunu varsayabiliriz -> (4 ) sonsuz bir döngüye dönüştürülür.
OP kodunun derleme kodunu, tanımlanmamış bir davranış olmadan aşağıdaki kodun derleme koduyla karşılaştırmamı sağladı.
#include <iostream>
int main()
{
// changed the termination condition
for (int i = 0; i < 3; ++i)
std::cout << i*1000000000 << std::endl;
}
Ve aslında, doğru kodun fesih koşulu vardır.
; ...snip...
L6:
mov ecx, edi
mov DWORD PTR [esp], eax
add esi, 1000000000
call __ZNSo3putEc
sub esp, 4
mov ecx, eax
call __ZNSo5flushEv
cmp esi, -1294967296 // here it is
jne L7
lea esp, [ebp-16]
xor eax, eax
pop ecx
; ...snip...
Aman Tanrım, bu tamamen belli değil! Adil değil! Ateşle yargılanmak istiyorum!
Bununla başa çık, buggy kodunu yazdın ve kendini kötü hissetmelisin. Sonuçları doğurun.
... veya alternatif olarak, daha iyi tanılama ve daha iyi hata ayıklama araçlarından uygun şekilde faydalanın.
Benim tarafımdan yazılmamış ve yarın gönderilmesi gereken bir programda spagetti karışıklığı var! YARDIM !!!!!! 111oneone
Gcc kullanın -fwrapv
Bu seçenek derleyiciye imzalı aritmetik toplama, çıkarma ve çarpma taşmasının ikişer tamamlayıcı gösterim kullanarak sarıldığını varsaymasını ister.
1 - §3.9.1.4'te belirtildiği gibi, bu kural "işaretsiz tam sayı taşması" için geçerli değildir
İmzasız olarak adlandırılan işaretsiz tamsayılar aritmetik modulo 2 n yasalarına uyacaktır ; burada n, belirli bir tamsayı boyutunun değer gösterimindeki bit sayısıdır.
ve örneğin sonucu UINT_MAX + 1
matematiksel olarak tanımlanır - aritmetik modulo 2 n kuralları ile