anonymous namespace and linkage

T

Taras_96

Hi everyone,

AFAIK external linkage allows you to refer to variables/functions
outside of the current translation unit. A variable in an unnamed
namespace is similar to declaring a static variable, but according to
the standard there is a difference:


"While this is essentially true in practical effect, there are subtle
differences. Using static as shown here causes "i" to have internal
linkage. When declared in an unnamed namespace without the use of
static, it has external linkage. This use of static is officially
deprecated (C++ Standard 7.3.1.1/2)."

To me this means that the variable is accessible outside of the
translation unit. However, Herb Schildt's book shows the following:
------------------------------------------------------------------------------------------
While the use of static global declarations is still allowed in C++, a
better way to
accomplish the same effect is to use an unnamed namespace. For
example:
File One
namespace {
int k;
}
void f1() {
k = 99; // OK
}

File Two
extern int k;
void f2() {
k = 10; // error
}
Here, k is also restricted to File One. The use of the unnamed
namespace rather than
static is recommended for new code.
------------------------------------------------------------------------------------------

So how is it that 'k' has external linkage?

Thanks

Taras
 
J

James Kanze

AFAIK external linkage allows you to refer to
variables/functions outside of the current translation unit. A
variable in an unnamed namespace is similar to declaring a
static variable, but according to the standard there is a
difference:
"While this is essentially true in practical effect, there are
subtle differences. Using static as shown here causes "i" to
have internal linkage. When declared in an unnamed namespace
without the use of static, it has external linkage. This use
of static is officially deprecated (C++ Standard 7.3.1.1/2)."
To me this means that the variable is accessible outside of
the translation unit. However, Herb Schildt's book shows the
following:
------------------------------------------------------------------------------------------
While the use of static global declarations is still allowed
in C++, a better way to accomplish the same effect is to use
an unnamed namespace. For example:
File One
namespace {
int k;}
void f1() {
k = 99; // OK
}
File Two
extern int k;
void f2() {
k = 10; // error}
Here, k is also restricted to File One. The use of the unnamed
namespace rather than static is recommended for new code.
------------------------------------------------------------------------------------------
So how is it that 'k' has external linkage?

It has external linkage, just like any other variable. In file
one, the definition is in a namespace with a name unique to the
file; in file 2, k is in global namespace. This is more or less
the same as if you had:

File One:
namespace TopSecrectName {
int k ;
}
using TopSecrectName ;
// ...

File Two
extern int k ;
// ...

Since the two k aren't in the same namespace, their qualified
names are different, and they can only be different entities.
 
J

James Kanze

<0c975cd6-22fb-4824-a4c7-4d5b58e49...@j22g2000hsf.googlegroups.com>,
Taras_96 said:
AFAIK external linkage allows you to refer to
variables/functions outside of the current translation unit.
A variable in an unnamed namespace is similar to declaring a
static variable, but according to the standard there is a
difference:
"While this is essentially true in practical effect, there
are subtle differences. Using static as shown here causes
"i" to have internal linkage. When declared in an unnamed
namespace without the use of static, it has external
linkage. This use of static is officially deprecated (C++
Standard 7.3.1.1/2)."
To me this means that the variable is accessible outside of
the translation unit. [...]
External linkage has other useful consequences as well. The
first that comes to mind is that the unnamed namespace allows
templates that are "local" to a translation unit. They must
have external linkage, and the unnamed namespace is the only
way to provide that WITHOUT making them accessible outside the
translation unit, since they cannot be static.

Not just templates, everything but references, variables and
functions. It's the only way to define a local, helper class
without risk of name conflict.
 
T

Taras_96

It has external linkage, just like any other variable.  In file
one, the definition is in a namespace with a name unique to the
file; in file 2, k is in global namespace.  This is more or less

Sorry, I don't think I made myself clear enough :*). I meant 'k' in
file 1 (ie: how is it that the 'k' in file 1 has external linkage?).
the same as if you had:

File One:
    namespace TopSecrectName {
    int k ;
    }
    using TopSecrectName ;
    //  ...

File Two
    extern int k ;
    //  ...

Since the two k aren't in the same namespace, their qualified
names are different, and they can only be different entities.

This I understand :). I might be getting confused over the meaning of
'external linkage'. To me the defining characteristic is that during
the linking stage, the linker can 'link in' that variable.

So you could have:

file 1:
int h = 1;

file 2;
extern int h; // <- this refers to the k defined in file 1

[Side note.. does the 'k' variable in the 'TopSecretName' namespace
have internal linkage only?]

So, if in fact my interpretation of 'external linkage' is correct, and
(in my original example) the 'k' variable in the anonymous namespace
does have external linkage, then how can we get file 2 to refer to the
k variable in file 1?

Thanks

Taras
 
T

Taras_96

......
There is no way for the compiler to figure out the right name for the
variable when compiler *another* translation unit.  That's the trick
to make it "not available".  The name is made up unique while the
compiler is compiling that particular translation unit.

I don't quite understand.. perhaps there's a typo?
Ugh!  Yuck!  I'm telling Mom!  ...Mom, Taras said the "S" name, and
he is reading THAT book!...

:) - point taken. Does it help that I'm reading it in conjunction with
Bjarne Stroustrup's book?
 
J

James Kanze

This I understand :). I might be getting confused over the
meaning of 'external linkage'. To me the defining
characteristic is that during the linking stage, the linker
can 'link in' that variable.

That's sort of it. Formally, it means that the fully qualified
name refers to the same entity in different translation units.
In this case, any reference to ::TopSecrectName::k in any
translation unit would refer to the same entity, the variable k
defined in File One. As a programmer, of course, there's no
possible way you could refer to ::TopSecrectName::k, because
there's no way you can know what TopSecrectName really is. For
the compiler, this isn't necessarily true; the compiler can
"leak" the TopSecrectName somehow, and may actually do so in
some strategies of template instantiation (particularly if
export is involved). But that's an implementation detail you're
not supposed to see:).
So you could have:
file 1:
int h = 1;
file 2;
extern int h; // <- this refers to the k defined in file 1
[Side note.. does the 'k' variable in the 'TopSecretName'
namespace have internal linkage only?]

No. It's just like any other variable. The only thing is that
the compiler generates a special name for the namespace, unique
to the translation unit.
So, if in fact my interpretation of 'external linkage' is
correct, and (in my original example) the 'k' variable in the
anonymous namespace does have external linkage, then how can
we get file 2 to refer to the k variable in file 1?

You can't, because you can't name the namespace its in.

In practice, you might be able to by looking at the mangled
generated name, demangling it to determine what the
TopSecretName actually was, and declaring a namespace with that
name. However, the compiler might use characters in that name
that you're not allowed to use in a name in C++ (g++ uses a . in
the name, for example), and its very likely that the compiler
generates a different name each time it recompiles the source
(true with both Sun CC and g++).
 
T

Taras_96

No.  It's just like any other variable.  The only thing is that
the compiler generates a special name for the namespace, unique
to the translation unit.


You can't, because you can't name the namespace its in.

In practice, you might be able to by looking at the mangled
generated name, demangling it to determine what the
TopSecretName actually was, and declaring a namespace with that
name.  However, the compiler might use characters in that name
that you're not allowed to use in a name in C++ (g++ uses a . in
the name, for example), and its very likely that the compiler
generates a different name each time it recompiles the source
(true with both Sun CC and g++).

I think I understand now.

In rough terms, the compiler generates a name for each namespace that
the linker can then use to link up matching namespaces. In the
anonymous namespace case, the compiler still generates that name (and
thus it has external linkage), but because that name is not visible to
the user (and the generation of that name is implementation specific),
then in practice you can't really refer to the anonyous namespace. If
you had the access to the generated name and the algorithm that
generates it, you could do something like this (in pseudo-code terms):

using inverse_generate_name(generated_anonymous_name_from file 1)

Sound about right ;)?

Taras
 
T

Taras_96

No.  It's just like any other variable.  The only thing is that
the compiler generates a special name for the namespace, unique
to the translation unit.


You can't, because you can't name the namespace its in.

In practice, you might be able to by looking at the mangled
generated name, demangling it to determine what the
TopSecretName actually was, and declaring a namespace with that
name.  However, the compiler might use characters in that name
that you're not allowed to use in a name in C++ (g++ uses a . in
the name, for example), and its very likely that the compiler
generates a different name each time it recompiles the source
(true with both Sun CC and g++).

I think I understand now.

In rough terms, the compiler generates a name for each namespace that
the linker can then use to link up matching namespaces. In the
anonymous namespace case, the compiler still generates that name (and
thus it has external linkage), but because that name is not visible to
the user (and the generation of that name is implementation specific),
then in practice you can't really refer to the anonyous namespace. If
you had the access to the generated name and the algorithm that
generates it, you could do something like this (in pseudo-code terms):

using inverse_generate_name(generated_anonymous_name_from file 1)

Sound about right ;)?

Taras
 
J

James Kanze

I think I understand now.
In rough terms, the compiler generates a name for each
namespace that the linker can then use to link up matching
namespaces. In the anonymous namespace case, the compiler
still generates that name (and thus it has external linkage),
but because that name is not visible to the user (and the
generation of that name is implementation specific), then in
practice you can't really refer to the anonyous namespace. If
you had the access to the generated name and the algorithm
that generates it, you could do something like this (in
pseudo-code terms):
using inverse_generate_name(generated_anonymous_name_from file 1)
Sound about right ;)?

It's exactly right. With the added aspect that most linkers
support more different characters in names that does C or C++,
so the compiler could insert characters which you couldn't even
use in a C++ name.

If you're curious about it, take a look at the mangled names the
compiler generates: compile something like:

namespace {
void function() {}
}

namespace KnownName {
void function() {}
}

and use nm (or the equivalent under Windows) to look at the
generated object file. (If you use a fairly long name for the
function, as I did above, you can pipe the output through grep,
and only see the relevant declarations.) Try recompiling: with
the two compilers I have handy (g++ and Sun CC), the name will
be different each time (and with g++, will contain a ., which
means that you cannot name it, even if you knew it).

The format of nm's output is implementation defined, but it
should also indicate that the symbols for both functions are
global.
 
G

gpderetta

It's exactly right.  With the added aspect that most linkers
support more different characters in names that does C or C++,
so the compiler could insert characters which you couldn't even
use in a C++ name.

If you're curious about it, take a look at the mangled names the
compiler generates: compile something like:

    namespace {
    void function() {}
    }

    namespace KnownName {
    void function() {}
    }

and use nm (or the equivalent under Windows) to look at the
generated object file.  (If you use a fairly long name for the
function, as I did above, you can pipe the output through grep,
and only see the relevant declarations.)  Try recompiling: with
the two compilers I have handy (g++ and Sun CC), the name will
be different each time (and with g++, will contain a ., which
means that you cannot name it, even if you knew it).

The format of nm's output is implementation defined, but it
should also indicate that the symbols for both functions are
global.

With a recent g++ the function in the anoymous namespace is optimized
away already at -O1, and nm doesn't show it. Even if the function has
extern linkage from the point of view of the standard, gcc treats it
as internal linkage for optimization purposes (for example it is free
to change calling conventions, as long as no pointers to it does
escape the translation unit), so even if one could figure out the
mangled name of the function, there is no way to refer to it from
another translation unit.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,769
Messages
2,569,579
Members
45,053
Latest member
BrodieSola

Latest Threads

Top