Undefined Behavior & Safety

the C abstract machine and the as-if rule

When you write a C program, you might picture the computer doing exactly what each line says, in order, step by step. That picture is wrong in a useful way. The C standard does not describe a real chip. Instead it describes an imaginary computer, called the abstract machine, and your program's MEANING is defined as what that imaginary machine would do. The real machine your code runs on is then free to take any shortcut it likes, as long as the visible result is the same.

The rule that allows this is called the as-if rule. It says the compiler may transform your program in any way it wants, provided the program behaves AS IF it had run on the abstract machine. What counts as 'visible' is a short, specific list called observable behavior: what you read from and write to volatile objects, the data written to files, and the prompts sent to interactive devices at the right moments. Everything else is fair game. If you write int x = 2 + 3; the compiler may compute 5 at compile time and never emit an add instruction. If you call a function whose result you ignore and that does nothing observable, the compiler may delete the call entirely. The order of two independent additions can be swapped. None of this changes the meaning, because the abstract machine's observable behavior is preserved.

Why this matters: it is the foundation under every later idea on this page. Optimization is not the compiler 'cheating' — it is the as-if rule being used honestly. But the as-if rule has a dark twin. The abstract machine's behavior is only defined when your program follows the rules. The moment your program does something the standard calls undefined behavior, the abstract machine has no defined behavior to preserve, so the as-if rule places NO constraint at all on the real machine. That is precisely why undefined behavior is so dangerous: the contract that protects you has been voided.

int f(void) { int x = 2 + 3; /* compiler may just produce 5 */ int y = x * 0; /* compiler may just produce 0 */ return y; /* whole function may collapse to: return 0; */ }

The abstract machine says this returns 0; the real machine is free to skip every step in between under the as-if rule.

The as-if rule is your friend ONLY while your program stays within defined behavior. Step into undefined behavior and the abstract machine has nothing left to preserve, so the rule stops protecting you and the optimizer is permitted to do anything.

Also called
abstract machineas-if ruleobservable behavior抽象機器可觀察行為