Signed integer overflow (secara tegas, tidak ada yang namanya "unsigned integer overflow") berarti perilaku tidak terdefinisi . Dan ini berarti apa pun bisa terjadi, dan mendiskusikan mengapa itu terjadi di bawah aturan C ++ tidak masuk akal.
C ++ 11 draft N3337: §5.4: 1
Jika selama evaluasi suatu ekspresi, hasilnya tidak didefinisikan secara matematis atau tidak dalam kisaran nilai yang dapat diwakili untuk jenisnya, perilaku tersebut tidak ditentukan. [Catatan: sebagian besar implementasi C ++ mengabaikan aliran bilangan bulat. Perawatan pembagian dengan nol, membentuk sisa menggunakan pembagi nol, dan semua pengecualian titik mengambang bervariasi di antara mesin, dan biasanya dapat disesuaikan dengan fungsi perpustakaan. —Kirim catatan]
Kode Anda dikompilasi dengan g++ -O3
peringatan emisi (bahkan tanpa -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)
^
Satu-satunya cara kita dapat menganalisis apa yang sedang dilakukan program, adalah dengan membaca kode assembly yang dihasilkan.
Berikut daftar perakitan lengkap:
.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
Saya bahkan hampir tidak bisa membaca perakitan, tetapi bahkan saya bisa melihat addl $1000000000, %edi
garis. Kode yang dihasilkan lebih mirip
for(int i = 0; /* nothing, that is - infinite loop */; i += 1000000000)
std::cout << i << std::endl;
Komentar @TC ini:
Saya menduga itu adalah sesuatu seperti: (1) karena setiap iterasi dengan i
nilai lebih besar dari 2 memiliki perilaku yang tidak terdefinisi -> (2) kita dapat mengasumsikan bahwa i <= 2
untuk keperluan optimasi -> (3) kondisi loop selalu benar -> (4) ) itu dioptimalkan menjadi loop tak terbatas.
memberi saya ide untuk membandingkan kode rakitan dari kode OP ke kode rakitan dari kode berikut, tanpa perilaku yang tidak ditentukan.
#include <iostream>
int main()
{
// changed the termination condition
for (int i = 0; i < 3; ++i)
std::cout << i*1000000000 << std::endl;
}
Dan, pada kenyataannya, kode yang benar memiliki kondisi terminasi.
; ...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...
OMG, itu sama sekali tidak jelas! Tidak adil! Saya menuntut pengadilan dengan api!
Hadapilah, Anda menulis kode buggy dan Anda akan merasa tidak enak. Tanggung konsekuensinya.
... atau, sebagai alternatif, gunakan diagnosa yang lebih baik dan alat debugging yang lebih baik - itulah gunanya:
Saya memiliki program spaghetti yang tidak ditulis oleh saya yang harus dikirim besok! BANTUAN !!!!!!
Gunakan gcc -fwrapv
Opsi ini menginstruksikan kompiler untuk mengasumsikan bahwa aritmatika yang ditandatangani dari penjumlahan, pengurangan dan multiplikasi membungkus menggunakan representasi dua-pelengkap.
1 - aturan ini tidak berlaku untuk "unsigned integer overflow", seperti §3.9.1.4 mengatakan itu
Bilangan bulat tak bertanda, dinyatakan tidak bertanda, harus mematuhi hukum modul hitung 2 n di mana n adalah jumlah bit dalam representasi nilai ukuran bilangan bulat tertentu.
dan misalnya hasil dari UINT_MAX + 1
didefinisikan secara matematis - dengan aturan modulithith 2 n