C++ Linkage, Constants, and Declarations Cheat Sheet¶
This document is a mental reset button for when C++ linkage rules fall out of your head (they will). Keep this nearby when working with headers, CMake projects, and embedded systems.
π Linkage (The Core Concept)¶
Linkage answers this question:
When the linker sees a name, does it refer to the same thing across translation units?
Types of Linkage¶
| Type | Meaning |
|---|---|
| Internal linkage | Each .cpp gets its own copy |
| External linkage | One shared symbol across all .cpps |
| No linkage | Exists only in its local scope |
π The One Definition Rule (ODR)¶
ODR Rule:
A symbol with external linkage must have exactly one definition in the entire program.
Violating this causes:
Headers are included into multiple translation units, so definitions in headers must be chosen carefully.
const¶
Key Facts¶
- At namespace scope,
consthas internal linkage - Safe to define in headers
- Each
.cppgets its own copy
Use When¶
- Value is constant
- You donβt need a single shared instance
Notes¶
- May still allocate storage
- Not always usable in compile-time contexts
constexpr β (Preferred for constants)¶
Key Facts¶
- Internal linkage by default
- Compile-time constant
- No storage unless needed
- Header-safe
Use When¶
- Pins
- Array sizes
- Template parameters
- Anything that should never change
π This should be your default choice
inline variables (C++17+)¶
Key Facts¶
- External linkage
- Allowed to appear in multiple translation units
- Linker merges them into one
Use When¶
- You want a single shared variable
- Defined in a header
- Global state is intentional
β οΈ Overuse = global-state hell
extern¶
Header (Declaration Only)¶
ONE .cpp (Definition)¶
Key Facts¶
- Declares a symbol that exists elsewhere
- Definition must appear exactly once
- Classic C-style global sharing
Use When¶
- Variable must be mutable (mutable = can change at runtime)
- Single shared instance is required
- Hardware state, global system flags
Forward Declarations with extern¶
Other .cpp files:
This avoids multiple definitions while allowing global access.
enum / enum class (Zero-linkage constants)¶
Key Facts¶
- No storage
- No linkage
- Impossible to violate ODR
Use When¶
- Pin numbers
- States
- Identifiers
π₯ Extremely safe and clean
β What NOT to Put in Headers¶
π§ Mental Cheat Rules¶
- Headers may declare, not define (unless constexpr / inline)
constexprfor constantsexternfor shared mutable datainlinefor header-defined shared variables- Enums are safest when possible
- If the linker yells β ODR violation
Recommended Default Choices¶
| Scenario | Use |
|---|---|
| Pin numbers | constexpr or enum class |
| Global mutable state | extern |
| Header-only shared variable | inline |
| Compile-time value | constexpr |
| Never want linker issues | enum |
Miranda-approved β
If this rulebook feels annoying, that means youβre doing real C++.
inline vs extern Variables (Direct Comparison)¶
Both inline and extern create one shared variable across all .cpp files.
The difference is where and how the definition exists.
Side-by-Side Comparison¶
| Feature | extern |
inline (C++17+) |
|---|---|---|
| Definition location | Exactly ONE .cpp |
In the header |
| Header contains | Declaration only | Full definition |
| Storage | One shared instance | One shared instance |
| ODR-safe | Yes (if done correctly) | Yes (guaranteed) |
Requires .cpp file |
β Yes | β No |
| Style | Traditional / explicit | Modern / header-only |
| Best for | Core system state | Small shared utilities |
extern Example (Explicit Ownership)¶
Mental model:
βThis variable lives in exactly one place. Everyone else references it.β
inline Example (Header-Only)¶
Mental model:
βThis variable is defined everywhere, but the linker merges it into one.β
Choosing Between Them¶
| Situation | Use |
|---|---|
| Global system state | extern |
| Hardware / machine mode | extern |
| Header-only library | inline |
| Utility counters / flags | inline |
| If unsure | extern |
Important Notes¶
inlinedoes not mean fasterinlinedoes not imply compile-time constant- Both create one shared object
- Overusing either = global-state risk