[2026] C++ Linkage and Storage Duration: extern, static, thread_local
이 글의 핵심
External vs internal linkage, no linkage, and automatic/static/thread/dynamic storage. How static locals, anonymous namespaces, and thread_local interact with lifetime.
Linkage kinds
External linkage
Symbols visible to other translation units (e.g. non-inline int at namespace scope, non-static free functions).
다음은 cpp를 활용한 상세한 구현 코드입니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.
// file1.cpp
int globalVar = 10;
void func() {
std::cout << globalVar << std::endl;
}
// file2.cpp
extern int globalVar;
extern void func();
int main() {
std::cout << globalVar << std::endl;
func();
}
Internal linkage
static at file scope, or anonymous namespaces—not visible to other TUs.
아래 코드는 cpp를 사용한 구현 예제입니다. 코드를 직접 실행해보면서 동작을 확인해보세요.
static int internalVar = 10;
static void internalFunc() {
std::cout << internalVar << std::endl;
}
No linkage
Local variables inside functions.
Storage duration
Automatic
Locals and parameters—destroyed at end of block.
Static
Globals, static locals, static class members—lifetime for entire program (or TU for internal linkage).
thread_local
Per-thread storage; each thread has its own instance.
Dynamic
new/delete (or smart pointers)—lifetime until explicitly freed.
extern usage
Variable declaration
아래 코드는 cpp를 사용한 구현 예제입니다. 코드를 직접 실행해보면서 동작을 확인해보세요.
// globals.cpp
int globalCounter = 0;
// main.cpp
extern int globalCounter;
const with extern
If you need shared const objects across TUs, use extern const consistently.
Explicit template instantiation (advanced)
Separate compilation patterns for templates may use extern template declarations—see your compiler docs.
static keyword
Function-local static
Initialized once, first time control passes through—thread-safe since C++11 for static locals.
Class static members
Declared in class; defined in one .cpp (or inline static in-class in C++17).
Common problems
Static initialization order fiasco
Avoid cross-TU initialization dependencies; prefer function-local statics for lazy init.
Duplicate definitions of globals
Only one definition across TUs for entities with external linkage.
thread_local cost
Each thread has its own copy—use for thread-local caches, RNG state, etc.
FAQ
Q1: extern vs static at file scope?
A: extern declares something defined elsewhere (often with external linkage). static at file scope gives internal linkage—not visible outside the TU.
Q2: When is thread_local useful?
A: Per-thread caches, per-thread PRNGs, TLS-style state.
Q3: Static initialization order?
A: Use function-local static for lazy initialization to avoid cross-TU ordering bugs.
Q4: Why extern “C”?
A: To link with C code by disabling C++ name mangling on those declarations.
Q5: Should I avoid globals?
A: Prefer narrower scope, dependency injection, or singletons where appropriate.
Q6: Further reading?
A: Stroustrup, cppreference, compiler manuals.
Related posts (internal links)
Practical tips
Debugging
- Compiler warnings first.
- Minimal repro.
Performance
- Profile before optimizing.
Code review
- Follow team conventions.
Practical checklist
Before coding
- Right technique?
- Maintainable?
- Performance?
While coding
- Warnings fixed?
- Edge cases?
- Error handling?
During review
- Intent clear?
- Tests?
- Docs?