According to the standard,
A name having namespace scope (3.3.6) has internal linkage if it is the name of ... a non-volatile variable that is explicitly declared const
or constexpr
and neither explicitly declared
extern
nor previously declared to have external linkage
So there is a special rule that variables at namespace scope have internal linkage when const
or constexpr
even if they would otherwise have external linkage. I'm not entirely sure why this rule exists but I suspect it's to allow the compiler to inline const
variables and hence not allocate any storage for them at all. The extern
specifier explicitly overrides this and makes the variable have external linkage again.
providing an initializer for a variable overrides the extern
Now this is a bit different. By default a declaration of a variable is also a definition, but extern
suppresses this so you can declare a variable without defining it (i.e. because its definition is in another translation unit). But if you have an initializer then it overrides the extern
and the declaration once again becomes a definition. This isn't really related to the rules about internal and external linkage above.