13 / 163 · C++11 · 8 min
extern: Declare Shared Entities Instead of Duplicating Allocation
extern is commonly used to declare a variable defined elsewhere so multiple translation units refer to the same entity. Distinguish declaration from definition, and scope from linkage; an extern variable declaration with an initializer is usually a definition, and include guards will not eliminate duplicate definitions that appear in a header.
In this lesson
A Declaration Tells the Compiler How to Use a Name
extern int counter; usually declares a variable that already exists or that will be defined elsewhere; it does not provide the variable definition here. When the current source file is compiled, the compiler knows its type and can generate access code; when the program is linked, a conforming actual definition still has to be found. extern will not make the linker invent a missing variable out of thin air.
A common organization is to write the declaration in a header and write int counter = 0; in one source file. The source file itself also includes that header so the compiler can check that the declaration and the definition have matching types. The example places both in a single standalone program to demonstrate the relationship, but a real cross-file project should keep the same single-definition structure.
An Initializer Requires a Fresh Diagnosis
At namespace scope, extern int counter = 0; is a definition, not a "more explicit declaration". Placing it in an ordinary header that several translation units include produces multiple non-inline definitions. Header guards only prevent repeated inclusion within the same translation unit; they cannot merge definitions that belong to different translation units.
An ordinary function declaration already typically has external linkage, so you need not mechanically add extern just to call the function across files. Linkage describes whether names refer to the same entity; scope describes where a name can be looked up. A local extern declaration does not automatically extend that name's visibility to the whole file.
const and Shared Constants
An ordinary non-volatile const variable at namespace scope usually has internal linkage by default, unless extern, inline, or a prior external-linkage declaration applies. When you want to share one constant object, write extern const int limit; in the header and write const int limit = 10; in a source file that includes that declaration.
C++17 inline variables are suitable for providing a program-wide shared entity's definition directly in a header; constexpr and whether object identity is required should be considered separately. Publishing mutable global state increases coupling and concurrency burden, so extern is a tool for organizing existing shared entities, not an encouragement to make all state global.
Pitfalls
- extern is not a runtime dynamic lookup, and it does not mean the variable definition must appear earlier in the source text.
- Internal-linkage entities of the same name do not become a shared entity merely because another source file writes extern; unify the linkage convention of the declaration and the definition.
Run an example
Minimum C++11 · complete program · Download .cpp
#include <cassert>
#include <iostream>
extern int counter;
extern const int limit;
void increment() {
if (counter < limit) ++counter;
}
int counter = 0;
const int limit = 2;
int main() {
increment();
increment();
increment();
assert(counter == 2);
std::cout << counter << ' ' << limit << '\n';
}
Compile locally
g++ -std=c++11 -Wall -Wextra -Wpedantic -pthread basics-extern.cpp -o example && ./exampleExpected result
2 2
CHECK YOUR UNDERSTANDING
Close the answer. Explain it.
A header writes int total = 0; and two source files include it, causing a duplicate definition. Give a C++11 scheme for placing the declaration and the definition.
Show a reference answer
Keep extern int total; in the header and remove the initializer and the variable definition from the header. In exactly one source file, include that header and write int total = 0;. Other source files only include the header. Call sites then share one object with external linkage, and you do not violate the ODR by producing a definition in each translation unit.
Check the sources
Drafts and official chapters change. The version mark is only the example’s minimum.