External linkage for name inside unnamed namespace

不问归期 提交于 2019-12-12 13:26:36

问题


According to the clause 3.5/4 of C++ Standard:

An unnamed namespace or a namespace declared directly or indirectly within an unnamed namespace has internal linkage.

Simultanously in paragraph 7.3.1.1 we have note 96):

Although entities in an unnamed namespace might have external linkage, they are effectively qualified by a name unique to their translation unit and therefore can never be seen from any other translation unit.

How to explicitly make external linkage for name inside unnamed namespace and how to check that linkage is actually external if Standard guaranteed that there is no way to access name defined inside unnamed namespace from another translation unit?

In which cases doing explicit external linkage for name inside unnamed namespace is useful?


回答1:


How to explicitly make external linkage for name inside unnamed namespace

The only way I can think of is to give it C language linkage, so that its linkage name ignores the namespace qualification:

namespace {
  extern void f() { }      // has internal linkage despite 'extern'
  extern "C" void g() { }  // ignores linkage of namespace
}
void (*p)() = f;  // ensure 'f' won't be optimized away

(A strict reading of the standard suggests that g should have internal linkage, but that's not what compilers seem to do.)

and how to check that linkage is actually external if Standard guaranteed that there is no way to access name defined inside unnamed namespace from another translation unit?

Typically ELF compilers will implement internal linkage with non-global symbols, so you can compile the code and inspect the object file:

$ g++ -c linkage.cc
$ nm linkage.o
0000000000000000 t _ZN12_GLOBAL__N_11fEv
0000000000000007 T g
0000000000000000 D p

The mangled name of the unnamed namespace can vary between compilers, but demangling it will show:

$ nm -C  linkage.o
0000000000000008 t (anonymous namespace)::f()
0000000000000000 T g
0000000000000000 D p

The lowercase t shows that f has local visibility, meaning it can't be linked to from other object files. The uppercase T shows that g has external linkage.

This isn't guaranteed by the standard though, as ELF visibility is not part of the C++ standard, and some compilers implement linkage without using visibility even on ELF platforms, e.g. the EDG compiler produces a global symbol for the same code:

$ nm linkage.o
0000000000000008 T _ZN23_GLOBAL__N__7_link_cc_p1fEv
0000000000000004 C __EDGCPFE__4_9
0000000000000000 T g
0000000000000000 D p
$ nm -C linkage.o
0000000000000008 T (anonymous namespace)::f()
0000000000000004 C __EDGCPFE__4_9
0000000000000000 T g
0000000000000000 D p

So using extern "C" allows you to give a name external linkage even if it appears in an unnamed namespace, but that doesn't make the note correct, because you can refer to that name from other translation units, because it doesn't use the unnamed namespace scope. That suggests to me that the note is simply a leftover from C++03 when entities in unnamed namespaces didn't automatically have internal linkage, and the note should be corrected or removed (and indeed T.C. points out it was already removed by DR 1603).

In which cases doing explicit external linkage for name inside unnamed namespace is useful?

I can't think of any cases where it's useful.




回答2:


Re

In which cases doing explicit external linkage for name inside unnamed namespace is useful?

The need for external linkage was important for C++03 templates. E.g. a function pointer as template argument had to be a pointer to function of external linkage. For example, the following would not compile with a C++03 compiler:

template< void(*f)() >
void tfunc() { f(); }

#include <stdio.h>
static void g() { printf( "Hello!\n" ); }

int main()
{
    tfunc<g>();
}

It compiles fine with a C++11 compiler.

So, with C++11 the anonymous namespace mechanism for having external linkage yet no name conflicts between translation units, is only technically necessary for classes. A class has external linkage. One wouldn't want to have to choose class names that guaranteed did not occur in other translation units.

With C++11 the rules changed not only for template parameters, but for whether things in an anonymous namespace have external linkage or not. With C++03 an anonymous namespace had formally external linkage, possibly unless it is itself within an anonymous namespace (C++03 §3.5/4 last dash + C++03 §7.3.1.1/1). With C++11 an anonymous namespace has formally internal linkage.

This does not matter to the linker, because there's no linking of namespaces, but it matters as a formal device to describe linkage of things:

C++11 §3.5/4:

An unnamed namespace or a namespace declared directly or indirectly within an unnamed namespace has internal linkage. All other namespaces have external linkage. A name having namespace scope that has not been given internal linkage above has the same linkage as the enclosing namespace if it is the name of
— a variable; or
— a function; or
— a named class (Clause 9), or an unnamed class defined in a typedef declaration in which the class has the typedef name for linkage purposes (7.1.3); or
— a named enumeration (7.2), or an unnamed enumeration defined in a typedef declaration in which the enumeration has the typedef name for linkage purposes (7.1.3); or
— an enumerator belonging to an enumeration with linkage; or
— a template.


Before going on to your other questions, it's worth noting that this quote from the standard,

Although entities in an unnamed namespace might have external linkage, they are effectively qualified by a name unique to their translation unit and therefore can never be seen from any other translation unit.

is plain wrong, because an extern "C" entity is visible from other translation units regardless of what namespace it's declared in.

Happily, as I recall, notes are non-normative, i.e. they do not define the language.


Re

How to explicitly make external linkage for name inside unnamed namespace

just declare a non-const variable, or a function, as extern. you can declare a non-const variable, or a function, as extern "C", making the linkage extern but at the same time making the namespaces irrelevant as far as linking is concerned: the C language doesn't have them.

namespace {
    extern "C" void foo() {}    // Extern linkage
}  // namespace <anon>

void bar() {}  // Also extern linkage, but visible to other TUs.

Re

how to check that linkage is actually external

well, the linkage affects things like possible conflicts with the One Definition Rule, often abbreviated as the “ODR”, which in C++11 is §3.2.

So, one way to see the linkage in action is to link two object files generated from the above source, as if you had two translation units with that same source code:

C:\my\forums\so\088> g++ -c anon.cpp -o x.o & g++ -c anon.cpp -o y.o

C:\my\forums\so\088> g++ main.cpp x.o y.o
y.o:anon.cpp:(.text+0x0): multiple definition of `foo'
x.o:anon.cpp:(.text+0x0): first defined here
y.o:anon.cpp:(.text+0x7): multiple definition of `bar()'
x.o:anon.cpp:(.text+0x7): first defined here
collect2.exe: error: ld returned 1 exit status

C:\my\forums\so\088> _

The linker complains about multiple definitions of foo, because as with C language binding it appears, as far as the linker is concerned, as a non-inline external linkage member of the global namespace, with two (possibly conflicting) definitions.




回答3:


According to the standard[3.5/2]:

When a name has external linkage , the entity it denotes can be referred to by names from scopes of other translation units or from other scopes of the same translation unit

and

When a name has internal linkage , the entity it denotes can be referred to by names from other scopes in the same translation unit.

So basically if you can refer to something in a translation unit different from the one where this something has been defined then it has external linkage, otherwise it has internal linkage. So given the note from the question:

Although entities in an unnamed namespace might have external linkage, they are effectively qualified by a name unique to their translation unit and therefore can never be seen from any other translation unit.

We practically have a situation in which we have a name but we don't know it, hence no matter how hard we try we can't refer to it from the different translation unit. And it makes it indistinguishable from the one with internal linkage. So, in my opinion it is just a word juggling — if you can't distinguish one situation from another then they are the same.



来源:https://stackoverflow.com/questions/35288838/external-linkage-for-name-inside-unnamed-namespace

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!