The ``C++ Primer’’ book has a very interesting recommendation
to use postfix operators, only when necessary (on page 148 for the 5th version).
The authors shared the following in their book.
The prefix version avoids unnecessary work.
It increments the value and returns the incremented version.
The postfix operator must store the original value so that it
can return the unincremented value as its result."
For ints and pointers, the compiler can optimize away this extra work.
After reading this, I started to use prefix instead of postfix more often.
However, I have always been doubting the statement the authors made in their book,
until this moment.
To finally test the authors’ claim, I created the following program.
1
2
3
4
5
6
7
|
#include <iostream>
int main() {
long i=0, j;
j = i++;
j = ++i;
return 0;
}
|
Here is the assembly code for the above short code.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
|
_main: ## @main
.cfi_startproc
## %bb.0:
pushq %rbp
.cfi_def_cfa_offset 16
.cfi_offset %rbp, -16
movq %rsp, %rbp
.cfi_def_cfa_register %rbp
xorl %eax, %eax
movl $0, -4(%rbp)
movq $0, -16(%rbp) // assign 0 to i
// j = i++;
movq -16(%rbp), %rcx // move i from memory to register rcx
movq %rcx, %rdx // copy rcx to rdx
addq $1, %rdx // increment rdx
movq %rdx, -16(%rbp) // store rdx into i
movq %rcx, -24(%rbp) // store rcx into j
// j = ++i;
movq -16(%rbp), %rcx // move i from memory to rcx
addq $1, %rcx // increment rcx
movq %rcx, -16(%rbp) // move rcx into i
movq %rcx, -24(%rbp) // move rcx into j
popq %rbp
retq
.cfi_endproc
|
For postfix operators, the compiler indeed stores another copy in rcx
and then assign it to j. We use one more register for postfix operators.
1
2
3
4
5
6
7
8
9
|
// program 2
#include <iostream>
int main() {
long i=0, j;
i++;
++i;
return 0;
}
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
|
_main: ## @main
.cfi_startproc
## %bb.0:
pushq %rbp
.cfi_def_cfa_offset 16
.cfi_offset %rbp, -16
movq %rsp, %rbp
.cfi_def_cfa_register %rbp
xorl %eax, %eax
movl $0, -4(%rbp)
movq $0, -16(%rbp) // assign 0 to i
// i++;
movq -16(%rbp), %rcx // move i from memory to rcx
addq $1, %rcx // increment rcx by 1
movq %rcx, -16(%rbp) // store rcx back to i
// ++i;
movq -16(%rbp), %rcx
addq $1, %rcx
movq %rcx, -16(%rbp)
popq %rbp
retq
.cfi_endproc
|
If we just increment a variable by itself, it seems the
generated code would be the same for both postfix and prefix operators.