Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Incrementing a volatile variable in C

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.

like image 699
Chromatix Avatar asked Sep 22 '15 17:09

Chromatix


People also ask

Can you increment with ++ in C?

A program can increment by 1 the value of a variable called c using the increment operator, ++, rather than the expression c=c+1 or c+=1.

What is volatile modifier in C?

The volatile qualifier is applied to a variable when we declare it. It is used to tell the compiler, that the value may change at any time. These are some properties of volatile. The volatile keyword cannot remove the memory assignment. It cannot cache the variables in register.

How do you increment in C?

In C/C++, Increment operators are used to increase the value of a variable by 1. This operator is represented by the ++ symbol. The increment operator can either increase the value of the variable by 1 before assigning it to the variable or can increase the value of the variable by 1 after assigning the variable.

Can volatile be a variable in C?

A volatile keyword in C is nothing but a qualifier that is used by the programmer when they declare a variable in source code. It is used to inform the compiler that the variable value can be changed any time without any task given by the source code. Volatile is usually applied to a variable when we are declaring it.


1 Answers

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

like image 145
Shafik Yaghmour Avatar answered Sep 22 '22 06:09

Shafik Yaghmour