Keeping a measurement loop
An empty `for` loop has no effect and may disappear during optimization. Declaring its counter `uint64_t volatile i` keeps accesses to the counter in the generated code. Alternatively, an ordinary counter can assign to a volatile object once per iteration. These choices do not cost the same: the measured loop with a volatile store was about 80% faster than the one with a volatile counter. section 16.4
The qualifier `volatile` applies syntactically like `const` and `restrict`. Each access to a volatile object reloads its stored value, and each modification stores it. This blocks optimizations that assume the value cannot change unexpectedly, but it can also make code slower. TAKEAWAY: Qualify an object only when its access behavior needs this protection. section 19.5
A value changed before a long jump
A local `depth` value used after `setjmp` may be changed on a path that exits through `longjmp`. An optimizer cannot safely infer its value there from the normal return path. Declaring it `unsigned volatile depth = 0;` ensures subsequent accesses use the stored value; code that receives a pointer to `depth` must be amended accordingly. section 19.5
A signal handler creates a related problem: the compiler cannot predict when it will run, so objects it may change need volatile qualification. Volatile alone does not make an operation uninterruptible. A signal can arrive partway through a multi-instruction write and expose a partially updated value. To pass information between a handler and ordinary execution, use `volatile sig_atomic_t`, `atomic_flag`, or another lock-free atomic type; keep the handler's work small. section 19.6 section 19.7
Listing 16.7 Instrumenting three for loops with struct timespec
timespec_get(&t[0], TIME_UTC);
/* Volatile for i ensures that the loop is effected */
for (uint64_t volatile i = 0; i < iterations; ++i) {
/* do nothing */
}
timespec_get(&t[1], TIME_UTC);
/* s must be volatile to ensure that the loop is effected */
for (uint64_t i = 0; i < iterations; ++i) {
s = i;
}
timespec_get(&t[2], TIME_UTC);
/* Opaque computation ensures that the loop is effected */
for (uint64_t i = 1; accu0 < upper; i += 2) {
accu0 += i;
}
timespec_get(&t[3], TIME_UTC);
Compare the empty loop with a volatile counter, the loop with a volatile store, and the loop using an opaque computation. section 16.4

