Type Qualifiers
The logger has a maximum number of readings that must never change, a sensor register that changes on its own, and a counter shared by two threads. The type int says nothing about any of that. Type qualifiers add the missing promises, and the compiler holds you, and itself, to them.
The rule
Qualifiers are promises: const won't change, volatile might, restrict is alone.
const: the program will not modify it.
const int max_readings = 96;
max_readings = 100; /* compile error: assignment to a const */With pointers, the position of const matters. const char *label means the characters cannot be changed through label; char *const label means the pointer itself cannot be changed.
volatile: it may change outside the program's control. The compiler must perform every read and write exactly as written, instead of keeping a copy in a register. Use it for memory-mapped hardware registers and for flags set by a signal handler:
#include <signal.h>
volatile sig_atomic_t stop_requested = 0; /* set by a signal handler */restrict (C99): this pointer is the only way to reach that memory. It applies only to pointers. The programmer promises that while the pointer is in use, the object it points to is not also accessed through some other pointer, which lets the compiler optimise harder. memcpy declares its parameters restrict, which is why it must not be given overlapping buffers; memmove makes no such promise and handles overlap. Breaking a restrict promise is undefined behaviour.
void add_offset(size_t n, int *restrict out, const int *restrict in);_Atomic (C11): every access is indivisible between threads. Include <stdatomic.h> for friendly names like atomic_int:
#include <stdatomic.h>
atomic_int readings_taken = 0;
/* in any thread: */
readings_taken++; /* one indivisible read-modify-write */Atomics are an optional C11 feature; an implementation without them defines __STDC_NO_ATOMICS__. Note that volatile does not make an increment safe between threads. That job belongs to _Atomic or a mutex.
The shortcut
Turn each qualifier into a question about the variable:
- Should nothing ever change it? const
- Can something outside the program change it? volatile
- Is this pointer the only route to its memory? restrict
- Do several threads touch it at once? _Atomic
The maximum
Fixed at build time and never changed:
const int max_readings = 96;.
Drills
Answer fast — trust the rule.
Which qualifier suits a hardware status register that the sensor updates by itself?
Two threads both increment readings_taken. Which qualifier makes each increment indivisible?
What can restrict qualify?
Which standard function has restrict parameters and must not be given overlapping buffers?
Remember
- Qualifiers are promises: const won't change, volatile might, restrict is alone, and
_Atomicis indivisible. - Shortcut: ask the four questions (never changes, changed from outside, only route, shared by threads).
- Trap:
volatileis not thread safety, and breaking arestrictpromise is undefined behaviour.
