Reputation: 133
this is c code:
#include <stdio.h>
int main() {
int i = 1;
while (i) i++;
printf("%d\n", i);
}
running:
miglanigursimar@Miglanis-MacBook-Pro 002 % gcc main.c
miglanigursimar@Miglanis-MacBook-Pro 002 % ./a.out
0
miglanigursimar@Miglanis-MacBook-Pro 002 %
but optimising:
miglanigursimar@Miglanis-MacBook-Pro 002 % gcc -O3 main.c
and running
miglanigursimar@Miglanis-MacBook-Pro 002 % ./a.out
takes forever. why
Upvotes: 1
Views: 102
Reputation: 224052
Without optimization, GCC, in the particular configuration you are using with this particular code, mechanically generates code for while (i) i++;
that repeatedly tests i
and increments i
, continuing until the hardware wraps during the addition, making i
become zero, at which point the loop ends.
With optimization, GCC uses the fact that the C standard permits the compiler to assume that integer overflow will not occur in the program. Using this as an axiom, the fact that i
is initially one and is only ever increased (without ever overflowing) means that i
can never be zero. From that, we can conclude that a loop starting while (i)
never ends, and the “optimal” code to generate is an infinite loop.
Upvotes: 3
Reputation: 225007
This code assumes that signed integer overflow will wrap around from the largest representable value to the smallest representable value, and from there will eventually reach the value 0. However, the C standard only allows for wraparound of unsigned integers, not signed integers. Signed integer overflow is undefined behavior.
At lower optimization levels, this wraparound happens to be occurring, but because what you're doing is undefined behavior there is no guarantee of that. When you increase the optimization, the compiler takes advantage of the fact that signed integer overflow is not allowed by assuming it doesn't happen. So when it looks at the while loop, it takes that assumption into account and concludes that the loop doesn't end, and therefore generates an infinite loop.
Looking at the assembly code at -O3
confirms this:
main:
.LFB11:
.cfi_startproc
.p2align 4,,10
.p2align 3
.L2:
jmp .L2
.cfi_endproc
Here we see that i
and the condition are optimized away entirely and that an unconditional infinite loop is generated.
If you were to declare i
to have type unsigned int
, wraparound behavior is guaranteed and you'll get the result you expect.
Upvotes: 4