C 2018 6.7.3 8 says:
An object that has volatile-qualified type may be modified in ways unknown to the implementation or have other unknown side effects. Therefore any expression referring to such an object shall be evaluated strictly according to the rules of the abstract machine, as described in 5.1.2.3.…
Since *(volatile int*)0x1234;
is an expression referring to an object with volatile-qualified type, evaluating it must access the object. (This presumes that 0x1234
stands for a valid reference to some object in the C implementation, of course.)
Per C 2018 5.1.2.3 4:
In the abstract machine, all expressions are evaluated as specified by the semantics. An actual implementation need not evaluate part of an expression if it can deduce that its value is not used and that no needed side effects are produced (including any caused by calling a function or accessing a volatile object).
Per C 2018 6.5 1:
An expression is a sequence of operators and operands that specifies computation of a value, or that designates an object or a function, or that generates side effects, or that performs a combination thereof.
Thus, an expression specifies computation of a value. Paragraph 5.1.2.3 4 tells us that this evaluation is performed by the abstract machine, and 6.7.3 8 tells us the actual implementation performs this evaluation that the abstraction machine performs.
One caveat is that what constitutes “access” is implementation-defined. “Access” as defined by the C standard includes both reading and writing (C 3.1 1), but the C standard is unable to specify that it means reading from or writing to some particular piece of hardware.
To go further into language-lawyer, territory, C 6.3.2.1 2 tells us:
Except when it is the operand of the sizeof
operator, the unary &
operator, the ++
operator, the --
operator, or the left operand of the .
operator or an assignment operator, an lvalue that does not have array type is converted to the value stored in the designated object (and is no longer an lvalue); this is called lvalue conversion.
Thus, since *(volatile int*)0x1234;
is an lvalue, by dint of the *
operator, and is not the operand of the listed operators, it is converted to the value stored in the object. Thus, this expression specifies the computation of the value that is stored in the object.
volatile
. Withoutvolatile
, it is flagged aswarning: statement with no effect [-Wunused-value]
. To be totally clear, you could do:(void) *(volatile int *)0x1234;
– Chapel