Neden bu döngü üretmek "uyarı: yineleme 3 çağırır tanımsız davranış" çıkış 4 satırdan fazla? | Netgez.com
SORU
18 HAZİRAN 2014, ÇARŞAMBA


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
18 HAZİRAN 2014, ÇARŞAMBA


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ü

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

Bunu PaylaÅŸ:
  • Google+
  • E-Posta
Etiketler:

YORUMLAR

SPONSOR VÄ°DEO

Rastgele Yazarlar

  • Avast

    Avast

    27 NÄ°SAN 2006
  • iNCH

    iNCH

    20 Temmuz 2009
  • TouchePro

    TouchePro

    27 EYLÃœL 2007