本文介绍了为什么这个循环产生“警告:迭代3u调用未定义的行为”并输出4行以上?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧! 问题描述 正在编译: #include< iostream> int main() { for(int i = 0; i std :: cout< i * 1000000000 } 和 gcc 以下警告: 警告:iteration 3u调用未定义的行为[-Waggressive-循环优化] std :: cout ^ 我知道有一个有符号整数溢出。 我不能得到的是为什么 i 值被溢出​​操作破坏了。 我阅读了的答案为什么x86上的整数溢出与GCC导致无限循环?,但我仍然不清楚为什么这发生 - 我得到的未定义意味着任何可能发生但是此特定行为的根本原因是什么? 在线: http://ideone.com/dMrRKR 编译器: gcc(4.8) 解决方案签名的整数溢出(严格来说,没有无符号整数溢出这样的东西)意味着。这意味着任何可能发生,并讨论为什么它发生在C ++的规则下是没有意义的。 C ++ 11草案N3337:§5.4: sup> 1 如果在表达式求值过程中,结果不是数学定义的, b $ b它的类型的可表示的值,行为是未定义的。 [注意:大多数现有的C ++实现忽略整数溢出。处理除以零,使用零除数形成余数,并且所有浮点异常在机器中不同,并且通常可以通过库函数调整。 -end note] 您的代码编译为 g ++ -O3 即使没有 -Wall ) a.cpp: main()': a.cpp:11:18:warning:iteration 3u调用未定义的行为[-Waggressive-loop-optimizations] std :: cout< i * 1000000000 ^ a.cpp:9:2:note:包含循环 for(int i = 0; i ^ 我们可以分析程序正在做什么的唯一方法是读取生成的汇编代码。 这是完整的装配列表: .filea.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; .sc13; .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; .sc12; .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,and 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,and 15 .def __GLOBAL__sub_I_main; .sc13; .type 32; .endef __GLOBAL__sub_I_main: LFB1092: .cfi_startproc subl $ 28,%esp .cfi_def_cfa_offset 32​​ movl $ __ ZStL8__ioinit,%ecx 调用__ZNSt8ios_base4InitC1Ev movl $ ___ tcf_0,(%esp)调用_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 .identGCC:(i686-posix-dwarf-rev1, 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 我几乎不能读取程序集,但是我可以看到 addl $ 1000000000,%edi 线。 生成的代码看起来更像 for(int i = 0; / *没什么, * /; i + = 1000000000) std :: cout< i<< std :: endl; @TC的此评论: 我怀疑它是这样的:(1)因为每个迭代 i 任何大于2的值都有未定义的行为 - >可以假设 i 用于优化目的 - >(3)循环条件总是真 - >(4)它被优化为无限循环。 p> 让我想法将OP的代码的汇编代码与下面代码的汇编代码进行比较,没有未定义的行为。 #include< iostream> int main() { //改变终止条件 for(int i = 0; i std :: cout<< i * 1000000000 } 事实上,正确的代码有终止条件。 ; ... 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 //这里是 jne L7 lea esp,[ebp-16 ] xor eax,eax pop ecx ; ... snb ... o OMG,完全不明显!这不公平! 处理它,你写了buggy代码,你应该感到不舒服。承担后果。 ...或者,正确使用更好的诊断和更好的调试工具 - 这是他们的目的: 启用所有警告 Wall 是gcc选项,启用所有有用的警告,没有误报。这是您应该总是使用的最低限度。 gcc有许多其他警告选项,但是,它们没有启用 -Wall ,因为他们可能对误报警告 Visual C ++不幸的是落后于提供有用警告的能力。 使用调试标志进行调试 用于整数溢出 -ftrapv 在溢出时陷阱程序, Clang编译器优秀的: -fcatch-undefined-behavior 捕获了大量未定义行为的实例(注意:很多!=所有他们) p>我有一个意大利面条的程序不是由我写的,需要明天发货!帮助!!!!!! 111oneone 使用gcc的 -fwrapv p> 此选项指示编译器假定加法,减法和乘法的有符号算术溢出使用二进制补码表示。 1 - 此规则不适用于无符号整数溢出,如§3.9.1.4所述 无符号整数,声明为无符号,应遵守算术模2的算法 n 其中n是数字在整数的特定大小的值表示中的位。 UINT_MAX + 1 的结果在数学上通过算术模2定义 n Compiling this:#include <iostream>int main(){ for (int i = 0; i < 4; ++i) std::cout << i*1000000000 << std::endl;}and gcc produces the following warning:warning: iteration 3u invokes undefined behavior [-Waggressive-loop-optimizations] std::cout << i*1000000000 << std::endl; ^I understand there is a signed integer overflow.What I cannot get is why i value is broken by that overflow operation?I've read the answers to Why does integer overflow on x86 with GCC cause an infinite loop?, but I'm still not clear on why this happens - I get that "undefined" means "anything can happen", but what's the underlying cause of this specific behavior?Online: http://ideone.com/dMrRKRCompiler: gcc (4.8) 解决方案 Signed integer overflow (as strictly speaking, there is no such thing as "unsigned integer overflow") means undefined behaviour. And this means anything can happen, and discussing why does it happen under the rules of C++ doesn't make sense.C++11 draft N3337: §5.4:1 If during the evaluation of an expression, the result is not mathematically defined or not in the range of representable values for its type, the behavior is undefined. [ Note: most existing implementations of C++ ignore integer overflows. Treatment of division by zero, forming a remainder using a zero divisor, and all floating point exceptions vary among machines, and is usually adjustable by a library function. —end note ]Your code compiled with g++ -O3 emits warning (even without -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) ^The only way we can analyze what the program is doing, is by reading the generated assembly code.Here is the full assembly listing: .file "a.cpp" .section .text$_ZNKSt5ctypeIcE8do_widenEc,"x" .linkonce discard .align 2LCOLDB0: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_endprocLFE860:LCOLDE0:LHOTE0: .section .text.unlikely,"x"LCOLDB1: .textLHOTB1: .p2align 4,,15 .def ___tcf_0; .scl 3; .type 32; .endef___tcf_0:LFB1091: .cfi_startproc movl $__ZStL8__ioinit, %ecx jmp __ZNSt8ios_base4InitD1Ev .cfi_endprocLFE1091: .section .text.unlikely,"x"LCOLDE1: .textLHOTE1: .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 ___mainL4: 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), %eaxL6: movl %esi, %ecx movl %eax, (%esp) addl $1000000000, %edi call __ZNSo3putEc subl $4, %esp movl %eax, %ecx call __ZNSo5flushEv jmp L4 .p2align 4,,10L5: 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 L6L15: call __ZSt16__throw_bad_castv .cfi_endprocLFE1084: .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_endprocLFE1092: .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; .endefI can barely even read assembly, but even I can see the addl $1000000000, %edi line.The resulting code looks more likefor(int i = 0; /* nothing, that is - infinite loop */; i += 1000000000) std::cout << i << std::endl;This comment of @T.C.: I suspect that it's something like: (1) because every iteration with i of any value larger than 2 has undefined behavior -> (2) we can assume that i <= 2 for optimization purposes -> (3) the loop condition is always true -> (4) it's optimized away into an infinite loop.gave me idea to compare the assembly code of the OP's code to the assembly code of the following code, with no undefined behaviour.#include <iostream>int main(){ // changed the termination condition for (int i = 0; i < 3; ++i) std::cout << i*1000000000 << std::endl;}And, in fact, the correct code has termination condition. ; ...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, that's completely not obvious! It's not fair! I demand trial by fire!Deal with it, you wrote the buggy code and you should feel bad. Bear the consequences....or, alternatively, make proper use of better diagnostics and better debugging tools - that's what they are for:enable all warnings-Wall is the gcc option that enables all useful warnings with no false positives. This is a bare minimum that you should always use.gcc has many other warning options, however, they are not enabled with -Wall as they may warn on false positivesVisual C++ unfortunately is lagging behind with the ability to give useful warnings. At least the IDE enables some by default.use debug flags for debuggingfor integer overflow -ftrapv traps the program on overflow, Clang compiler is excellent for this: -fcatch-undefined-behavior catches a lot of instances of undefined behaviour (note: "a lot of" != "all of them") I have a spaghetti mess of a program not written by me that needs to be shipped tomorrow! HELP!!!!!!111oneoneUse gcc's -fwrapv This option instructs the compiler to assume that signed arithmetic overflow of addition, subtraction and multiplication wraps around using twos-complement representation. 1 - this rule does not apply to "unsigned integer overflow", as §3.9.1.4 says that Unsigned integers, declared unsigned, shall obey the laws of arithmetic modulo 2n where n is the number of bits in the value representation of that particular size of integer.and e.g. result of UINT_MAX + 1 is mathematically defined - by the rules of arithmetic modulo 2n 这篇关于为什么这个循环产生“警告:迭代3u调用未定义的行为”并输出4行以上?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!
10-30 08:48