[2026] C++ Linkage and Storage Duration: extern, static, thread_local

[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.

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?

C++, linkage, storage, extern, static

... 996 lines not shown ... Token usage: 63706/1000000; 936294 remaining Start-Sleep -Seconds 3