the sequenced-before relation
/ SEE-kwenst /
When does one part of an expression happen before another? In a single thread, you might assume code runs strictly top to bottom, but within a single expression C gives the compiler freedom to reorder and overlap sub-computations. The sequenced-before relation is the precise rule for which evaluations are ordered, which are unordered, and where the boundaries are — and it is what decides whether code like i = i++ is well-defined.
Older C used SEQUENCE POINTS: certain points (the end of a full expression at a semicolon, the comma operator, &&, ||, ?:, and a function call's argument evaluation before the call) at which all prior side effects must be complete. C11 reframed this with three relations between evaluations A and B: sequenced-before means A is fully ordered before B; if neither is sequenced before the other they are UNSEQUENCED (the implementation may do them in any order or interleave them); and INDETERMINATELY SEQUENCED means one happens entirely before the other but you do not know which (this is how separate function calls relate). The rule that bites: if two side effects on the same object, or a side effect and a read of it, are unsequenced, the behavior is undefined.
It matters because it is the foundation of the as-if rule and of what counts as observable behavior: the compiler may reorder anything as long as the sequenced-before-visible results are preserved. The classic traps are exactly the unsequenced cases — a = a++, arr[i] = i++, or f(g(), h()) where g and h are unsequenced relative to each other — none of which you should write.
int i = 1; i = i++; // UNDEFINED: two unsequenced side effects on i int a[3], j = 0; a[j] = j++; // UNDEFINED: write a[j] and update j are unsequenced // well-defined instead: i++; or a[j] = 0; j++;
Two unsequenced modifications of i (or a write and an update of j) are undefined behavior, not merely 'unpredictable'.
Unsequenced side effects on the same object are undefined behavior — the compiler may assume it never happens and optimize accordingly, so the result is not just 'some order', it has no defined meaning at all.