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/dMrRKR
Compiler: gcc (4.8)
Best Answer
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
Your code compiled with
g++ -O3
emits warning (even without-Wall
)The only way we can analyze what the program is doing, is by reading the generated assembly code.
Here is the full assembly listing:
I can barely even read assembly, but even I can see the
addl $1000000000, %edi
line. The resulting code looks more likeThis comment of @T.C.:
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.
And, in fact, the correct code has termination condition.
Unfortunately this is the consequences of writing buggy code.
Fortunately you can make 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 debugging
-ftrapv
traps the program on overflow,-fcatch-undefined-behavior
catches a lot of instances of undefined behaviour (note:"a lot of" != "all of them"
)Use gcc's
-fwrapv
1 - this rule does not apply to "unsigned integer overflow", as §3.9.1.4 says that
and e.g. result of
UINT_MAX + 1
is mathematically defined - by the rules of arithmetic modulo 2n