In deference to the other answers posted, I feel you deserve to see an example of all three techniques in action. the following is highly situational, but none-the-less demonstrates what can happen:
The Code
#include <stdio.h>>
int i=1;
int main()
{
printf("i=%d\n", i);
printf("i++ : %d\n", i++);
printf("++i : %d\n", ++i);
i = i + 1;
printf("i=i+1 : %d\n", i);
return 0;
}
The Tools
Using clang 3.3 optimization set to -O2
The Assembly Listing
Cleaned and annotated for consumption:
; Basic printf()
movl _i(%rip), %esi
leaq L_.str(%rip), %rdi
xorb %al, %al
callq _printf
; post-increment (i++)
movl _i(%rip), %esi
leal 1(%rsi), %eax
movl %eax, _i(%rip)
leaq L_.str1(%rip), %rdi
xorb %al, %al
callq _printf
leaq L_.str2(%rip), %rdi
; pre-increment (++i)
movl _i(%rip), %esi
incl %esi
movl %esi, _i(%rip)
xorb %al, %al
callq _printf
leaq L_.str3(%rip), %rdi
; traditional (i = i + 1)
movl _i(%rip), %esi
incl %esi
movl %esi, _i(%rip)
xorb %al, %al
callq _printf
The Difference
The stark difference is the storage of a temporary containing the prior value of i
before increment in the case of i++
vs ++i
. This is solely because said-temp is used as an argument to the printf()
function invoke. Also note that in both the pre-increment and traditional mechanic, the resulting optimized assembly is identical (movl, incl, movl
).
So does it make a difference if the post-increment operation is not evaluated ?
int main()
{
i++;
printf("i=%d\n", i);
++i;
printf("i=%d\n", i);
i = i + 1;
printf("i=%d\n", i);
return 0;
}
With the resulting assembling being:
; post-increment
movl _i(%rip), %esi
incl %esi
movl %esi, _i(%rip)
leaq L_.str(%rip), %rbx
movq %rbx, %rdi
xorb %al, %al
callq _printf
; pre-increment
movl _i(%rip), %esi
incl %esi
movl %esi, _i(%rip)
movq %rbx, %rdi
xorb %al, %al
callq _printf
; traditional
movl _i(%rip), %esi
incl %esi
movl %esi, _i(%rip)
movq %rbx, %rdi
xorb %al, %al
callq _printf
Note that the rbx
magic you see is unrelated and simply a way for caching the shared format string for printf()
. In all three cases the identical code (movl,incl,movl
) is used.
Conclusion
For a stand-alone statement, clang 3.3 will optimize all three to the same resulting code. If you introduce an evaluation dependance, post-increment and pre-increment can (and likely will) emit differing code. If your increment is a stand-alone statement, it makes no difference which you choose.