Storage classes (auto, register, static, extern) control a variable's lifetime (how long it lives) and linkage/scope (where it's visible). The preprocessor runs before compilation, handling #include, #define macros and conditional compilation through pure text substitution. Both are classic interview ground.
A static local variable keeps its value between function calls and is initialised once. A static global/function limits visibility to its own file. extern declares something defined elsewhere (shared across files). #define creates a macro the preprocessor substitutes as raw text — with no type checking.
void counter(void) {
static int count = 0; // initialised once; persists across calls
count++;
printf("%d ", count);
}
// counter(); counter(); counter(); -> 1 2 3#define PI 3.14159 #define SQUARE(x) ((x) * (x)) // parenthesise EVERYTHING int a = SQUARE(2 + 3); // ((2 + 3) * (2 + 3)) = 25, thanks to parens
- A static local variable is initialised once and keeps its value across calls — perfect for counters — while still being scoped to that function. 'static' on a global instead means 'private to this file'.
- Macros are blind text substitution with no type checking, so always wrap parameters and the whole body in parentheses. #define SQUARE(x) x*x turns SQUARE(2+3) into 2+3*2+3 = 11, not 25 — a classic bug.
- Both live for the whole program (static storage duration).
- A global is visible everywhere (across files, unless made static); a static local is visible only inside its function.
- So static local gives you persistence without exposing the variable — lifetime of a global, scope of a local.
- Macros substitute text literally before compilation, ignoring precedence.
- Without parentheses, SQUARE(2+3) expands to 2+3*2+3, which is 11, not 25.
- Wrapping each parameter and the whole expression in parentheses preserves the intended grouping.
- Macro side effects: SQUARE(i++) increments i twice — macros re-evaluate their arguments.
- 'static' means different things for a local (persistence) vs a global/function (file-private).
- The preprocessor runs before compilation and does no type checking — macro bugs aren't caught like function bugs.