You should look at the assembler code to see what your compiler really does with the code. For gcc / clang / icc you can use Matt Godbolt Compiler Explorer .
clang optimizes everything because of UB, and the result ( foo is the first version, foo2 is the second version:
foo:
icc considers both versions very similar:
foo: pushq %rbp #4.1 movq %rsp, %rbp #4.1 subq $2000000, %rsp #4.1 movl -4(%rbp), %eax #8.9 movl %eax, x(%rip) #8.5 leave #10.1 ret #10.1 foo2: pushq %rbp #13.1 movq %rsp, %rbp #13.1 subq $2000000, %rsp #13.1 movl -1000004(%rbp), %eax #18.9 addl -4(%rbp), %eax #18.24 movl %eax, x(%rip) #18.5 leave #19.1 ret
and gcc creates different assembler code for a different version. Version 6.1 creates code that will show similar behavior as your experiments:
foo: pushq %rbp movq %rsp, %rbp subq $2000016, %rsp movl 1999996(%rsp), %eax movl %eax, x(%rip) leave ret foo2: pushq %rbp movl $1000016, %edx
Thus, the only way to understand the difference is to look at the assembler code generated by the compiler , everything else just wonders.
ead
source share