c language · advanced

C: volatile — What It Does (and Doesn't)

volatile tells the compiler that an object may change outside the normal program flow, so it must not cache or optimize away accesses: every read re-reads memory and every write actually occurs, preserving program order among volatile accesses. Its legitimate uses are narrow — memory-mapped hardware registers, sig_atomic_t flags set by signal handlers, and locals that must survive setjmp/longjmp — places where a value can change without the compiler being aware, which is why a non-volatile spin loop on such a value can be optimized to a single read and loop forever. The critical point for interviews is what volatile does NOT provide: it is not atomic (++counter is still a read-modify-write), it establishes no happens-before relationship, and it imposes no memory ordering with respect to other CPUs, so a volatile variable shared and mutated across threads is still a data race. (This is the C/C++ meaning; Java and C# give volatile acquire/release semantics.) For inter-thread communication use C11 _Atomic / <stdatomic.h> or C++ std::atomic, which provide both atomicity and a memory model; a variable may be both _Atomic and volatile when it is simultaneously hardware-visible and thread-shared.

🔑 Key line

C volatile stops the compiler caching/eliding accesses (every read re-reads memory) for hardware registers and signal flags — but it is NOT atomic and NOT a memory barrier, so it cannot make multithreaded code correct; use _Atomic/std::atomic for that.

The code

volatile int* reg = (int*)0x4000; // memory-mapped hardware register
while (*reg == 0) {} // re-read every iteration (not cached)
volatile sig_atomic_t flag = 0; // set by a signal handler
while (!flag) {} // compiler won't hoist the read
// volatile is NOT a synchronization or atomicity primitive:
volatile int counter;
++counter; // STILL a data race across threads

What this lesson walks through

  1. 01volatile = 'this value can change behind your back'
  2. 02What volatile does NOT give you
  3. 03Gotcha — volatile is NOT for threads
  4. 04Use _Atomic / atomics for threads

volatile tells the compiler that an object may change outside the normal program flow, so it must not optimize away or cache accesses: every read re-reads from memory and every write actually happens, in program order relative to other volatile accesses. Its real uses are memory-mapped hardware registers and variables touched by a signal handler — places where the value can change without the compiler seeing it.

See it animated — step by step, at your own pace

Unlock the full interactive walkthrough of C: volatile — What It Does (and Doesn't) and 100+ animated C++ interview lessons.

← Previous
C: static, extern & Linkage
Next →
C: Integer Promotion & Signed/Unsigned