Consider the following three expressions:
++x;
x += 1;
x = x + 1;
As far as I'm aware, they are identical in semantics, ignoring operator overloading in C++. However, today I read an assertion that they are different, specifically when x
is declared volatile
.
To test this assertion, I wrote the following and compiled it for PowerPC, AMD64, ARMv6 and 68k:
#include <stdint.h>
static volatile uint64_t x = 0;
void a(void)
{
++x;
}
void b(void)
{
x += 1;
}
void c(void)
{
x = x + 1;
}
On all four of these platforms, the three functions produced identical assembler output, whether at -O1 or -O3. On AMD64, that was just two instructions:
incq _x(%rip)
retq
Therefore, is there any truth behind that assertion? If so, what is the difference, and how can I expose it?
NB: I'm perfectly aware that volatile
doesn't guarantee atomicity. That's not what I'm asking about here - unless the atomicity itself is what is different between the three.
From the draft C++ standard section 5.3.2
[expr.pre.incr] says:
If x is not of type bool, the expression ++x is equivalent to x+=1
and 5.17
[expr.ass] says:
The behavior of an expression of the form E1 op = E2 is equivalent to E1 = E1 op E2 except that E1 is evaluated only once.
So ++x
and x += 1
are equivalent.
Now the one case where x += 1
differs from x = x + 1
is that E1
is only evaluated once. In this particular case it does not matter but we can come up with a case where it does:
#include <stdint.h>
volatile uint64_t x = 0;
volatile uint64_t y[2] = {0} ;
void c(void)
{
y[x] = y[x] + 1;
}
in this case the x
will be evaluated twice as opposed to this case:
void b(void)
{
y[x] += 1;
}
and a godbolt session shows for b()
:
b(): # @b()
movq x(%rip), %rax
incq y(,%rax,8)
retq
and for c()
:
c(): # @c()
movq x(%rip), %rax
movq y(,%rax,8), %rax
incq %rax
movq x(%rip), %rcx
movq %rax, y(,%rcx,8)
retq
As far as I can tell this applies to C11 as well. From C11 section 6.5.3.1
Prefix increment and decrement operators:
The expression ++E is equivalent to (E+=1).
and from section 6.5.16.2
Compound assignment:
Acompound assignment of the form E1 op= E2 is equivalent to the simple assignment expression E1 = E1 op (E2), except that the lvalue E1 is evaluated only once
Collected from the Internet
Please contact [email protected] to delete if infringement.
Comments