'Is `*(volatile T*)0x1234;` guaranteed to translate into read instruction?

When working with hardware it is sometimes required to perform a read from a specific register discarding the actual value (to clear some flags, for example). One way would be to explicitly read and discard the value such as:

int temp = *(volatile int*)0x1234; // 0x1234 is the register address
(void)temp;                          // To silence the "unused" warning

Another way that seem to work is simply:

*(volatile int*)0x1234;

But this doesn't seem to obviously imply the read access, yet it seems to translate to one on compilers I checked. Is this guaranteed by the standard?

Example for ARM GCC with -O3: https://arm.godbolt.org/z/9Vmt6n

void test(void)
{
    *(volatile int *)0x1234;
}

translates into

test():
        mov     r3, #4096
        ldr     r3, [r3, #564]
        bx      lr


Solution 1:[1]

The gcc documentation on volatile tells us that what consititues a volatile access is implementation defined:

C has the concept of volatile objects. These are normally accessed by pointers and used for accessing hardware or inter-thread communication. The standard encourages compilers to refrain from optimizations concerning accesses to volatile objects, but leaves it implementation defined as to what constitutes a volatile access. The minimum requirement is that at a sequence point all previous accesses to volatile objects have stabilized and no subsequent accesses have occurred. Thus an implementation is free to reorder and combine volatile accesses that occur between sequence points, but cannot do so for accesses across a sequence point. The use of volatile does not allow you to violate the restriction on updating objects multiple times between two sequence points.

This is backed up by C11 section 6.7.3 Type qualifiers p7:

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. Furthermore, at every sequence point the value last stored in the object shall agree with that prescribed by the abstract machine, except as modified by the unknown factors mentioned previously.134) What constitutes an access to an object that has volatile-qualified type is implementation-defined.

The gcc document goes on to specify how volatile works for gcc, for the case similar to your says:

A scalar volatile object is read when it is accessed in a void context:

volatile int *src = somevalue;
*src;

Such expressions are rvalues, and GCC implements this as a read of the volatile object being pointed to.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Shafik Yaghmour