This violates ODR (UB, no diagnostic is required).
One and only one definition of every non-inline function or variable that is odr-used is required to appear in the entire program (including any standard and user-defined libraries). The compiler is not required to diagnose this violation, but the behavior of the program that violates it is undefined. https://en.cppreference.com/w/cpp/language/definition#One_Definition_Rule
I don't understand what is happening with this program. I think both ns are different variables (so there is no ODR violation) because of [namespace.unnamed]:
An unnamed-namespace-definition behaves as if it were replaced by
n (from a.cpp) = 10; n (from b.cpp) = 21
n (from a.cpp) = 10; n (from b.cpp) = 22
n (from a.cpp) = 10; n (from b.cpp) = 23
n (from a.cpp) = 10; n (from b.cpp) = 24
But GCC and Clang produce:
n (from a.cpp) = 10; n (from b.cpp) = 21
n (from a.cpp) = 10; n (from b.cpp) = 22
n (from a.cpp) = 11; n (from b.cpp) = 22
n (from a.cpp) = 11; n (from b.cpp) = 23
I tried several linkers with Clang and GCC: ld, lld, and gold. No change.
I suspect there is a name lookup bug. I'm not sure which behavior is correct. MSVC's compiler flag /permissive- affects name lookup but didn't make any difference here.
I see. I just wanted to understand the limitations of extern. Apparently, extern can't be used to declare a variable that exists in another compilation unit if it would cause a naming conflict .
The example I gave is probably flawed. If I wanted a function from file1.cpp to modify a variable from file2.cpp, the variable being modified should have scope (e.g., contained in a class) or, if in global scope, be named so as to avoid name clash.