Neden bu döngü üretmek "uyarı: yineleme 3 çağırır tanımsız davranış" çıkış 4 satırdan fazla?
Bu derleme:
#include <iostream>
int main()
{
for (int i = 0; i < 4; i)
std::cout << i*1000000000 << std::endl;
}
ve gcc
aşağıdaki uyarı oluşturur:
warning: iteration 3u invokes undefined behavior [-Waggressive-loop-optimizations]
std::cout << i*1000000000 << std::endl;
^
İmzalı tamsayı taşması var anladığım kadarıyla.
Ben alamıyorum ne i
değeri taşma işlemi tarafından bozuldu neden?
Why does integer overflow on x86 with GCC cause an infinite loop?, cevapları okudum ama hala net değil benimnedenbu durumda ben "" "her şey mümkün", ama temel nedeni budur . demek tanımlanmamış ^em>bu belirli davranış?
Online: http://ideone.com/dMrRKR
Derleyici: gcc (4.8)
CEVAP
Tamsayı taşması (doğrusu, diye bir şey yok "işaretsiz tamsayı taşması") anlamına gelir . imzalı ^em>tanımsız davranış. Ve bu her şey olabilir anlamına gelir, ve neden C kuralları çerçevesinde oluyor tartışmak mantıklı değil.
C 11 taslak N3337: 5.4§:1
Aralığında bir ifade değerlendirme sırasında, sonuç matematiksel olarak tanımlı değil ya da değil kendi türü için değerleri gösterilebilir, davranış tanımsızdır. [ Not: çoğu mevcut uygulamaları C tamsayı taşmaları görmezden. Sıfıra bölme, kalan sıfır bölen kullanarak şekillendirme ve tedavisi kayan nokta özel durumlar makineleri arasında değişir ve genellikle bir kütüphane işlevi ile ayarlanabilir. —son not ]
Kodunuz g -O3
ile derlenmiş uyarı (bile -Wall
olmadan) yayar
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)
^
Tek yolu programın ne yaptığını analiz edebiliriz, üretilen assembly kodu okuyarak.
Ä°ÅŸ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), êx
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, ìx
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), ìx
.cfi_def_cfa 1, 0
andl $-16, %esp
pushl -4(ìx)
pushl ëp
.cfi_escape 0x10,0x5,0x2,0x75,0
movl %esp, ëp
pushl íi
pushl %esi
pushl ëx
pushl ìx
.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 íi, íi
subl $24, %esp
call ___main
L4:
movl íi, (%esp)
movl $__ZSt4cout, ìx
call __ZNSolsEi
movl êx, %esi
movl (êx), êx
subl $4, %esp
movl -12(êx), êx
movl 124(%esi,êx), ëx
testl ëx, ëx
je L15
cmpb $0, 28(ëx)
je L5
movsbl 39(ëx), êx
L6:
movl %esi, ìx
movl êx, (%esp)
addl $1000000000, íi
call __ZNSo3putEc
subl $4, %esp
movl êx, ìx
call __ZNSo5flushEv
jmp L4
.p2align 4,,10
L5:
movl ëx, ìx
call __ZNKSt5ctypeIcE13_M_widen_initEv
movl (ëx), êx
movl 24(êx), íx
movl $10, êx
cmpl $__ZNKSt5ctypeIcE8do_widenEc, íx
je L6
movl $10, (%esp)
movl ëx, ìx
call *íx
movsbl %al, êx
pushl íx
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, ìx
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
Montaj bile zar zor okuyabiliyorum, ama bile addl $1000000000, íi
satırını görebiliyorum.
Sonuç koduyla daha fazla gibi görünüyor
for(int i = 0; /* nothing, that is - infinite loop */; i = 1000000000)
std::cout << i << std::endl;
Bu @T. C. yorum:
Onun gibi bir şey olduğunu düşünüyorum: (1) Herhangi bir değer 2'den büyük
i
ile her yineleme tanımsız davranış var çünkü>(2)i <= 2
iyileştirme amaçlı - ^ için varsayabiliriz . (3) döngü, koşul her zaman doğru ->(4) uzak, sonsuz bir döngüye optimize edildi.
bana fikir aşağıdaki kod derleme kod OP kod derleme kod, tanımsız davranış ile karşılaştırmak verdi.
#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 kodu fesih şartı 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...
OMG, bu tamamen belli değil! Bu hiç adil değil! Ateşle imtihan talep ediyorum!
Anlaşma, buggy kodu yazdın ve kendini kötü hissetmelisin. Sonuçlarına katlanın.
...ya da, alternatif olarak, daha iyi tanı ve daha iyi hata ayıklama araçları doğru şekilde kullanın - siz ne yapıyorsunuz
tüm uyarıları etkinleştir
-Wall
hiç yanlış pozitif ile tüm yararlı uyarılar sağlayan gcc seçenektir. Bu her zaman kullanmanız gereken minimum.- gcc has many other warning options ancak, yanlış pozitif uyar olabilir
-Wall
ile etkin değiller - Visual C ne yazık ki yararlı uyarılar vermek yeteneği ile geride kalıyor. En azından IDE varsayılan olarak bazı sağlar.
hata ayıklama hata ayıklama bayrakları kullanın
- tamsayı taşması
-ftrapv
taşma programı yakalar - Çınlama derleyici bunun için mükemmel: tanımsız davranış örnekleri (not:
"a lot of" != "all of them"
)-fcatch-undefined-behavior
yakalar bir sürü
- tamsayı taşması
Yarın sevk edilmesi gereken bir program bana göre değil yazılı spagetti bir karmaşa var! !!!!!YARDIM!111oneone
Kullanımı gcc -fwrapv
Bu seçeneği derleyici aritmetik taşma imzalanan ek varsayalım bildirir, çıkarma ve çarpma ikişer-tamamlayıcı gösterimi kullanarak sarar.
1- bu kural uygulanmaz. "işaretsiz tamsayı taşması §3.9.1.4 diyor.",
İmzasız ilan eder aritmetik yasaları modül 2 işaretsiz tam itaatnn numarasıdır tamsayı, belirli büyüklükte değer gösterimi bit.
ve UINT_MAX 1
örneğin sonucu aritmetik kurallar 2 modül tarafından matematiksel olarak tanımlanmışn
Böyle büyük mükafat uyarı: "Birde...
PHP: "Uyarı: Tanımsız değişken&qu...
&; Kullanarak " " birden fazla ka...
&Quot;hack" teknik olarak tanımsı...
Neden TextBox ekleme yapar.Bir döngü s...