Skip to main content
๐Ÿ“œ WAYPOINT LESSON

Sequencing, Side Effects, and the Unsequenced Trap

โญโญโญ advancedโณ 15 min read๐Ÿ“ Lesson 154 of 225

Sequencing points, unsequenced traps, and the review rule that survives.

What is ordered, what is not

Within an expression, C defines sequencing points (C11+: sequenced before relations):

  • &&, ||, , (comma operator), ?: โ€” left side fully evaluated (all side effects done) before right.
  • End of a full expression; initializer boundaries.

Everything else โ€” operands of +, function arguments, subscripts โ€” is unsequenced relative to each other.

int i = 0;
int a[2] = {0, 0};
int k = i++ + i++;      /* UB: i modified twice without sequencing */
int j = f() + g();      /* fine, but f/g call order is UNSPECIFIED */
a[i] = i++;             /* UB: unsequenced read and write of i */

The rule that survives code review

If an expression both (1) modifies an object and (2) reads or modifies that same object anywhere else, and those two actions are unsequenced โ€” the program is UB. Not "platform-dependent": undefined.

Splitting into statements is the portable cure:

int t = i++;
a[i] = t;               /* now sequenced: the read of i happens before the store */

Unspecified is not a license either

f() + g() is well-defined C, but you cannot know which side runs first. Side effects in unsequenced argument lists (printf("%d %d", i++, i)) are not UB โ€” but their output is unpredictable, and relying on it produces real damage.