Store ordering for larger-than-native-size type - C spec

90 Views Asked by At

Suppose you have a pointer to a larger-than-native-type integer, what do recent C specs say regarding the store ordering? E.g.:

volatile uint64_t *test = (volatile uint64_t *)(addr);
*test = 0;

On a 32-bit architecture this will compile to two stores, does the C spec say anything about which store will be first (addr or addr+4)? Or is it implementation defined?

2

There are 2 best solutions below

4
chux - Reinstate Monica On

what do recent C specs say regarding the store ordering?

The endian is implementation defined.

does the C spec say anything about which store will be first (addr or addr+4)?

It is implementation defined. It may be simultaneous. It does not even need to be consistent.

0
Lundin On

The C standard says nothing of the store order. It likely happens in the order of addressing, meaning that the data at the lowest address likely gets copied first (MS bytes on big endian, LS bytes on little endian). Likely (but not guaranteed) since copying in the order of addresses is what makes most sense on most ISA, particularly those with data cache.


Somewhat related:

What the C standard (5.1.2.3) does guarantee is that the whole 64 bits will get copied in between the two sequence points here:

... ;      // the semi colon is a sequence point
*test = 0; // the semi colon is a sequence point

No atomicity is guaranteed since _Atomic qualifiers weren't used. So the access may get interrupted halfways by a context switch to another thread or process - the access isn't guaranteed to be thread-safe.

5.1.2.3 isn't the best part of the standard, but if you read it literally then it also says that instruction reordering cannot happen across a volatile object, essentially making it act as a memory barrier.

However, another "language lawyer" aspect is that the C standard has always been broken since C90, speaking of volatile objects rather than a volatile lvalue access. In your code here, the pointed-at data is not necessarily a volatile object, maybe only the pointer is. Since the compiler might not know what's stored at the address you cast the pointer from, or what "effective type" and qualifiers that object got. This language "bug" is going to be fixed in the upcoming C23 standard that defines and uses the term volatile access instead.