Linkage of identifiers in C++ declared with the specifier extern - c++

In the C Standard (6.2.2 Linkages of identifiers) there is written enough clear
4 For an identifier declared with the storage-class specifier extern
in a scope in which a prior declaration of that identifier is
visible,31) if the prior declaration specifies internal or external
linkage, the linkage of the identifier at the later declaration is the
same as the linkage specified at the prior declaration. If no prior
declaration is visible, or if the prior declaration specifies no
linkage, then the identifier has external linkage.
However I can not find a similar statement in the C++ Standard looking through its section 6.5 Program and linkage.
The question arises due to the following quote from the C++ 17 Standard
3 A name having namespace scope (6.3.6) has internal linkage if it is
the name of
(3.2) — a non-inline variable of non-volatile const-qualified type
that is neither explicitly declared extern nor previously declared to
have external linkage; or
Now consider the following declarations
const int x = 100;
extern const int x;
So it is unclear whether the code is ill-formed or the constant x has internal linkage though it is declared with the specifier extern or the Standard has a defect in the description of this paragraph or I missed the quote in the C++ Standard similar to the quote from the C Standard.

Maybe a defective in basic.link#6, After looking at the dcl.stc#5, it says:
For the linkage of a name declared with an extern specifier, see [basic.link].
However, the rule about declaration declared with a extern specifier is mostly in [basic.link#6], which is:
The name of a function declared in block scope and the name of a variable declared by a block scope extern declaration have linkage. If such a declaration is attached to a named module, the program is ill-formed. If there is a visible declaration of an entity with linkage, ignoring entities declared outside the innermost enclosing namespace scope, such that the block scope declaration would be a (possibly ill-formed) redeclaration if the two declarations appeared in the same declarative region, the block scope declaration declares that same entity and receives the linkage of the previous declaration. If there is more than one such matching entity, the program is ill-formed. Otherwise, if no matching entity is found, the block scope entity receives external linkage. If, within a translation unit, the same entity is declared with both internal and external linkage, the program is ill-formed.
It sounds like that these rules only applies to block scope declaration instead of applying to namespace scope declaration that declared with extern specifier. Except for this paragraph, there is no more rule in section [basic.link] that indicates what the linkage of a name declared by extern specifier. Unlike what says in C standard, the rules apply to whatever declarations declared with extern specifier(regardless of what kind of scopes where the declarations declared).

Related

does linkage rules apply to namespace just like global names?

I've read Translation units and linkage, and it says:
The concept of linkage applies only to global names. The concept of linkage does not apply to names that are declared within a scope. A scope is specified by a set of enclosing braces such as in function or class definitions.
It says "The concept of linkage applies only to global names" but didn't mention namespace scope. However, I saw namespace scope in some case we have to use extern to make some variables available in other files:
// constants.h
#ifndef CONSTANTS_H
#define CONSTANTS_H
namespace Constants
{
// since the actual variables are inside a namespace,
// the forward declarations need to be inside a namespace as well
extern const double pi;
extern const double avogadro;
extern const double my_gravity;
}
#endif
// constants.cpp
namespace Constants
{
// actual global variables
extern const double pi(3.14159);
extern const double avogadro(6.0221413e23);
extern const double my_gravity(9.2); // m/s^2 -- gravity is light on this planet
}
So what is the official definition? Is it true that linkage concept only apply to global, maybe namespace is part of global?
Namespaces are orthogonal to the distinction between global and local symbols. Namespaces just augment the name of a symbol, they don't change anything else. So, if you have a global variable, and put it inside a namespace it is still global variable, with external linkage.
The exception is when you put something inside an unnamed namespace. In this case, since there is no possible way code in one source file could reference a symbol in an unnamed namespace declared in another file, it is effectively a static symbol, and thus effectively has internal linkage.
Linkage applies to names basic.link/3:
A name is said to have linkage when it might denote the same object, reference, function, type, template, namespace or value as a name introduced by a declaration in another scope:
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.
When a name has module linkage, the entity it denotes can be referred to by names from other scopes of the same module unit ([module.unit]) or from scopes of other module units of that same module.
When a name has internal linkage, the entity it denotes can be referred to by names from other scopes in the same translation unit.
When a name has no linkage, the entity it denotes cannot be referred to by names from other scopes.
Names of variables at namespace scope have external linkage unless they meet certain exceptions. basic.link/5.8 For example, non-extern const variables at namespace scope have internal linkage. basic.link/4.2
And yes, global scope is a namespace scope. basic.scope.namespace/4
Here is the relevant section of the spec pertaining to linkage.
And a relevant snippet:
Indicating by default namespaces have external linkage, minus the exceptions given.

Why is it the case that the name of the function f4 has internal linkage, and not a C language linkage?

The fifth example in [dcl.link]/4 states the following:
extern "C" {
static void f4(); // the name of the function f4 has internal linkage (not C language linkage)
// and the function’s type has C language linkage.
}
Why is this? Why is it the case that the name of the function f4 has internal linkage, and not a C language linkage?
P.S.: I'm asking this from a perspective of a language-lawyer. That is, how can one derive the commented statement above, from normative paragraphs in the Standard?
From that same section, emphasis mine:
In a linkage-specification, the specified language linkage applies to the function types of all function declarators, function names with external linkage, [...]
But, f4 is declared static, which means that name has internal linkage per [basic.link]/3:
A name having namespace scope has internal linkage if it is the name of:
a variable, function or function template that is explicitly declared static; or, [...]
Hence, the C linkage doesn't apply.

Why can't I define a variable at global scope after declaring it in an unnamed namespace?

In my understanding:
Names declared in an unnamed namespace are added to the enclosing namespace scope and visible in that translation unit.
With the extern specifier, a variable is not automatically defined (default-initialized).
I would expect the following to declare a variable and then define the same variable:
// Declare ::<unnamed>::my_obj with internal linkage and add my_obj to the
// enclosing namespace scope (the global namespace scope).
namespace { extern int my_obj; }
// Expected: Define the variable declared above.
// Actual: Declare and define a new object, ::my_obj.
int my_obj(42);
Instead, it declares two different objects, and warns me about the unused extern int my_obj.
Why doesn't the second my_obj define the first my_obj? Isn't it in scope?
The statement "names declared in an unnamed namespace are added to the enclosing namespace scope" does not mean that members of unnamed namespace become full-fledged members of enclosing namespace. This addition is performed by an implicit using-directive. Such addition makes these names visible to name lookup, but does not make them literal members of the enclosing namespace for other purposes.
The problem you have in your code is the same as the one in the following snippet
namespace A
{
void foo();
}
using namespace A;
void foo() // <- Defines `::foo`, not `A::foo`
{
}
// `A::foo` remains undefined
Despite the fact that we explicitly "added" names from A to the global namespace, it still does not mean that we can define A::foo as a member of global namespace using unqualified name foo.
In order to define A::foo in the above example you still have to refer to it using its qualified name A::foo. With unnamed namespaces this is impossible for obvious reasons.
P.S. Compilers typically implement unnamed namespaces as namespaces with internal compiler-generated names. If you somehow figured out a "hack" to discover that name, technically you'd probably be able to define your my_obj separately by using a qualified name in the definition. But keep in mind that the hidden namespace name is different in different translation units, thus producing a unique my_obj variable in each translation unit.
An unnamed namespace is not a global namespace. It is a specific namespace that is visible only within the translation unit in which it appears.
This cppreference page describes this in more detail.
If you are trying to use a symbol defined in an unnnamed namespace within the same translation unit -- just use it! It's in scope. You don't need an extern
from https://msdn.microsoft.com/en-us/library/2tx32sw2.aspx :
A variable declared with the extern storage-class specifier is a reference to a variable with the same name defined at the external level in any of the source files of the program. The internal extern declaration is used to make the external-level variable definition visible within the block. Unless otherwise declared at the external level, a variable declared with the extern keyword is visible only in the block in which it is declared.
Since the object is declared in a namespace, it must be defined in the same namespace (or rather, if a name is used as a declaration in one namespace and a definition outside that namespace, it refers to two different entities). That it is visible at file scope does not mean that it is a member of that namespace; I think the assertion that —
Names declared in an unnamed namespace are added to the enclosing
namespace scope
— does not mean what you think it does.
The C++11 standard says that An unnamed-namespace-definition behaves as if it were replaced by:
[inline] namespace unique { /* empty body */ }
using namespace unique ;
namespace unique { namespace-body }
(paraphrasing slightly for formatting; the initial "inline" is optional, appearing iff it appears in the unnamed namespace definition).
So, would you expect in this:
namespace a_name {
extern int a;
}
using namespace a_name;
int a = 4;
... that the first mention of a (inside the namespace) would declare the variable and the second define it? (If you would, at least this is consistent. But if you wouldn't, you need to recognize that the standard specifically says that you should get the same behavior from the unnamed namespace).
I don't believe there is any mechanism to declare a member in one namespace and provide the definition for the same member within another namespace, even if the member is visible in the second namespace.
To address comments below:
Yes, extern causes the declaration not to be a definition. I have removed the statement saying that extern had no effect, which was mainly in reference to linkage; that extern does not grant a name within the unnamed namespace external linkage is true, since C++11 (including amendments). Although in C++03 it may have technically granted external linkage, this was only as an attribute of the declaration/definition; the symbol was still not visible outside the translation unit and had no special visibility to the linker. The significance of extern on a member of the unnamed namespace in C++03 then apparently boils down to usability of that member as a constant expression, if it is a const-qualified pointer.
The example that was linked in a comment, following another comment stating that the linkage determined visibility of symbols to the linker which can have consequences, was perhaps intended to demonstrate that (in C++11) symbols in the unnamed namespace can have external linkage, and that non-external linkage pointers cannot be used as as template arguments (i.e. contexts requiring a constant expression) even when declared const. It did indeed fail to compile with GCC, however it compiles successfully with Clang and with the Intel compiler Icc. With any of the three compilers, the symbols declared in the inline namespace are local symbols at the link level (as can be seen using objdump for example) - there is no causal relationship between symbol visibility at the linker level and the error produced.C++11 explicitly makes a statement (3.5) to the effect that
extern-qualified symbols shall have internal linkage if they
reside in the unnamed namespace (specifically: 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 ...). Furthermore, const-declared variables with internal linkage should be usable in contexts requiring a constant expression. By reading the standard, there can be little argument that the GCC compiler is behaving incorrectly in this case.

Are global variables extern by default or is it equivalent to declaring variable with extern in global?

I have gone through following two questions:
static and extern global variables in C and C++
global variable in C are static or not?
Both questions says the two things in different way.
Question 1's Answer:
Global variables are not extern nor static by default on C and C++.
Question 2's Answer:
If you do not specify a storage class (that is, the extern or static keywords), then by default global variables have external linkage
I need to know the following:
Are global variables extern by default in linkage (or) is it equivalent to declaring variables by specifying extern storage class?
Are global variables static by default in scope (or) is it equivalent to declaring variables by specifying static storage class?
Is there any difference with C or C++? Can anyone please clarify?
is global variables are extern by default in linkage (or) it is equivalent to declaring variable by specifying extern storage class?
The default storage duration, scope and linkage of variables declared outside any block, at the outer most level, have static storage duration, file scope and external linkage. C11 standard says that:
6.2.1 Scopes of identifiers (p4):
[...] If the declarator or type specifier that declares the identifier appears outside of any block or list of parameters, the identifier has file scope, which terminates at the end of the translation unit. [...]
6.2.2 Linkages of identifiers (p5):
[...] If the declaration of an identifier for an object has file scope and no storage-class specifier, its linkage is external.
6.2.4 Storage durations of objects (p3):
An object whose identifier is declared without the storage-class specifier
_Thread_local, and either with external or internal linkage or with the storage-class specifier static, has static storage duration.
So, if x is global
int x;
then its storage duration, scope and linkage is equivalent to x in
extern int x;
is global variables are static by default in scope (or) it is equivalent to declaring variable by specifying static storage class?
No. As I stated above that its duration is static and it has file scope.
If there is any c or c++ difference please clarify?
No difference. Rule is same in both languages.
is global variables are extern by default in linkage (or) it is equivalent to declaring variable by specifying extern storage class?
Unless otherwise specified, they have external linkage (except in C++, where they have internal linkage if they're constant).
The first answer you link to is saying that it's not equivalent to declaring it extern (which makes it a pure declaration, not a definition); not that it doesn't have external linkage.
is global variables are static by default in scope (or) it is equivalent to declaring variable by specifying static storage class?
In C++, they have internal linkage (as if declared static) if they are constant, external linkage otherwise. In C, they always have external linkage.
If there is any c or c++ difference please clarify?
As mentioned above, the default is always external linkage in C, while in C++ it's internal for constant variables.
Verified by using gcc version9.3.0:
Global variables are extern by default.

Can a variable be declared both static and extern?

Why the following doesn't compile?
...
extern int i;
static int i;
...
but if you reverse the order, it compiles fine.
...
static int i;
extern int i;
...
What is going on here?
This is specifically given as an example in the C++ standard when it's discussing the intricacies of declaring external or internal linkage. It's in section 7.1.1.7, which has this exert:
static int b ; // b has internal linkage
extern int b ; // b still has internal linkage
extern int d ; // d has external linkage
static int d ; // error: inconsistent linkage
Section 3.5.6 discusses how extern should behave in this case.
What's happening is this: static int i (in this case) is a definition, where the static indicates that i has internal linkage. When extern occurs after the static the compiler sees that the symbol already exists and accepts that it already has internal linkage and carries on. Which is why your second example compiles.
The extern on the other hand is a declaration, it implicitly states that the symbol has external linkage but doesn't actually create anything. Since there's no i in your first example the compiler registers i as having external linkage but when it gets to your static it finds the incompatible statement that it has internal linkage and gives an error.
In other words it's because declarations are 'softer' than definitions. For example, you could declare the same thing multiple times without error, but you can only define it once.
Whether this is the same in C, I do not know (but netcoder's answer below informs us that the C standard contains the same requirement).
For C, quoting the standard, in C11 6.2.2: Linkage of identifiers:
3) If the declaration of a file scope identifier for an object or a function contains the storage-class specifier static, the identifier has internal linkage.
4) For an identifier declared with the storage-class specifier extern in a scope in which a prior declaration of that identifier is visible, if the prior declaration specifies internal or external linkage, the linkage of the identifier at the later declaration is the same as the
linkage specified at the prior declaration. If no prior declaration is visible, or if the prior declaration specifies no linkage, then the identifier has external linkage.
(emphasis-mine)
That explains the second example (i will have internal linkage). As for the first one, I'm pretty sure it's undefined behavior:
7) If, within a translation unit, the same identifier appears with both internal and external linkage, the behavior is undefined.
...because extern appears before the identifier is declared with internal linkage, 6.2.2/4 does not apply. As such, i has both internal and external linkage, so it's UB.
If the compiler issues a diagnostic, well lucky you I guess. It could compile both without errors and still be compliant to the standard.
C++:
7.1.1 Storage class specifiers [dcl.stc]
7) A name declared in a namespace scope without a storage-class-specifier has external linkage unless it has
internal linkage because of a previous declaration and provided it is not declared const. Objects declared
const and not explicitly declared extern have internal linkage.
So, the first one attempts to first gives i external linkage, and internal afterwards.
The second one gives it internal linkage first, and the second line doesn't attempt to give it external linkage because it was previously declared as internal.
8) The linkages implied by successive declarations for a given entity shall agree. That is, within a given scope,
each declaration declaring the same variable name or the same overloading of a function name shall imply
the same linkage. Each function in a given set of overloaded functions can have a different linkage, however.
[ Example:
[...]
static int b; // b has internal linkage
extern int b; // b still has internal linkage
[...]
extern int d; // d has external linkage
static int d; // error: inconsistent linkage
[...]
In Microsoft Visual Studio, both versions compile just fine.
On Gnu C++ you get an error.
I'm not sure which compiler is "correct". Either way, having both lines doesn't make much sense.
extern int i means that the integer i is defined in some other module (object file or library). This is a declaration. The compiler will not allocate storage the i in this object, but it will recognize the variable when you are using it somewhere else in the program.
int i tells the compiler to allocate storage for i. This is a definition. If other C++ (or C) files have int i, the linker will complain, that int i is defined twice.
static int i is similar to the above, with the extra functionality that i is local. It cannot be accessed from other module, even if they declare extern int i. People are using the keyword static (in this context) to keep i localize.
Hence having i both declared as being defined somewhere else, AND defined as static within the module seems like an error. Visual Studio is silent about it, and g++ is silent only in a specific order, but either way you just shouldn't have both lines in the same source code.