Such an object is normally accessed by pointers and used for accessing hardware. In most expressions, it is intuitively obvious what is a read and what is a write. For example
volatile int *dst = somevalue; volatile int *src = someothervalue; *dst = *src;
will cause a read of the volatile object pointed to by src and store the
value into the volatile object pointed to by dst. There is no
guarantee that these reads and writes are atomic, especially for objects
However, if the volatile storage is not being modified, and the value of the volatile storage is not used, then the situation is less obvious. For example
volatile int *src = somevalue; *src;
According to the C standard, such an expression is an rvalue whose type
is the unqualified version of its original type, i.e.
GCC interprets this as a read of the volatile object being pointed to or
only as a request to evaluate the expression for its side-effects depends
on this type.
If it is a scalar type, or on most targets an aggregate type whose only member object is of a scalar type, or a union type whose member objects are of scalar types, the expression is interpreted by GCC as a read of the volatile object; in the other cases, the expression is only evaluated for its side-effects.