Initializer overrides extern [duplicate] - c++

I am very very sorry. I didn't know my incomplete code attachment would create such a mess. I am very glad to see so many sincere helps.
This code will compile:
int myadd(int, int);
static int main_stat = 5;
int main()
{
int i, j;
main_stat = 13;
j = myadd(-1,7);
i = main_stat;
cout << j << i; // 3 and 13
return 0;
}
myadd.cpp
extern int main_stat = -3;
int myadd(int x,int y)
{
int t = main_stat;
t = x + y;
y = t +main_stat;
return y; // will return 3
}
See I defined and extern linking main_stat. Why is that legal? I thought you could only link and not define.
Is storage allocated in the stack frame of myadd function call? Global static are allocated on heap, I believe, right?
EDIT
I am sorry, but I think this time I will narrow down my questions:
From C++ Primer 4ed
An extern declaration may include an initializer (when combined
becomes definition) only if it appears outside a function.
I am clear about one-definition rule.
Q1. Which copy of main_stat does myadd(int,int) uses when it is called? The same copy as the main has, but with a different value (which I can test) ? Or does each function has its own static global copy?
Q2. Is memory allocated on the heap for these global static variables? I know many things are up to implementation, but isn't heap used for static variables?
Q3. I know the followings two are valid
extern int x; // means int x is defined elsewhere
extern int x = 3; // declared and defined
Why do we want the second one if we can just declare a static global variable within the namespace of myadd ? How does it make things clear like aschepler said?

All variable declarations with an initializer are also definitions;
that's an overriding rule. Regardless of extern. There are even
cases where you need an extern on a definition: you can only
instantiate a template using a variable which has external linkage. And
const variables have internal linkage by default, so you need
something like:
extern int const i = 42;
if you want to use it to instantiate a template<int const*>.

The following is a declaration and definition:
int x;
Adding extern says "make it a declaration only, please".
But when you are providing a value, the line has to be a definition, so the variable gets extern storage class and you just happen to be defining it right in place anyway:
extern int x = 3;
The linkage semantics are as they usually are for extern, and the storage location is just as it would be for a normal definition int x = 3 — i.e. in that TU at namespace scope. myadd is not relevant at all.
It's a hard one to "prove", because it's a case of "there's no rule against it".
Here's the best quote:
[n3290: 3.1/2]: A declaration is a definition unless it declares
a function without specifying the function’s body (8.4), it
contains the extern specifier (7.1.1) or a linkage-specification25 (7.5) and neither an initializer nor a
function-body, [..]
And some other pertinent information:
[n3290: 3.5/2]: 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 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.
[n3290: 3.5/12]: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 there is a visible declaration of an entity with
linkage having the same name and type, ignoring entities declared
outside the innermost enclosing namespace scope, 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. [..]

extern int main_stat=-3;
declares and defines main_stat, While:
extern int main_stat;
just declares the variable main_stat.
You can have as many declarations as you want but you can have only one Definition.
The keyword extern, indicates External Linkage. Without it main_stat would be static and have Internal linkage and you cannot not use main_stat from another translation unit.
Is storage allocated in the stack frame of myadd ?
No definitely not on the stackframe of add.
Where the memory is allocated is implementation defined but you have the assurance that the object will be alive throughout the duration of the program.

The question apparently stems from some misconception.
Some people believe that extern keyword always turns a definition into a non-defining declaration. This is simply not true.
The keyword extern simply gives the declared entity external linkage. It can be applied to declarations. It can be applied to definitions (and remember that definitions are declarations as well).
So, saying that one can't define an extern entity is absolutely incorrect. One can. There's no problem with that at all.
The confusion is usually caused by the fact that when you apply extern to a definition like
int x; // no initializer
that definition suddenly turns into a non-defining declaration. This is true, but this is is no more than a one-off quirk of extern keyword that has to be remembered. If you take a definition like
int x = 42;
then applying the extern keyword to it will still preserve it as a definition, i.e. no quirks in this case.

First, according to your comment, the file containing the main function has the definition static int main_stat = 10;. You should be aware that this is not the same variable as you defined in the file containing myadd because as static variable its scope is restricted to that file. Indeed, thanks to that static variable with the same name, main is not able to access the variable you defined in this file.
But that doesn't mean that either variable was created on the stack. Both are separate global variables, it's just that the variable main_stat in the file containing main (I'll call that file main file for short, and this one myadd file) is not available in any other file, while the variable main_stat you defined here can be accessed from any file which contains the declaration extern main_stat; (note: without initializer!). The main file cannot contain this declaration, however, because it would conflict with the static variable of the same name.
Note that giving an initializer makes your declaration of the variable a definition, that is, it's the same as if you had omitted the extern (note however that if a variable is declared constant, the extern may not be omitted because constants are by default static). The only global extern declarations which are not also definitions are those with extern, but without initializer.

Everyone else has covered this pretty well, but just to show the variants in one place:
int x; // #1
is a declaration and definition. The initial value of x is zero.
int x = 3; // #2
is a declaration and definition.
const int cx; // #3
is illegal in C++.
const int cx = 3; // #4
is a declaration and definition, but cx has internal linkage if this is its first declaration in the translation unit.
extern int x; // #5
is a declaration but NOT a definition. There must be a definition of x somewhere else in the program.
extern int x = 3; // #6
is a declaration and a definition. The extern is unnecessary, but makes things clear.
extern const int cx; // #7
is a declaration but NOT a definition. There must be a definition of cx somewhere else in the program.
extern const int cx = 3; // #8
is a declaration and a definition. The extern is needed unless the previous declaration above was already seen.

Related

Is it valid to use extern in a local scope to unshadow a global variable?

Is this extern declaration in a nested local scope a valid and defined way to bring the global a back into the scope?
int a = 1; // may be in another file
void main() {
int a = 2; // hides the global
{
cout << a << endl; // prints 2
cout << ::a << endl; // obviously 1
extern int a;
cout << a << endl; // also prints 1
}
}
This is a valid use of extern, though an obscure one. According to the C++20 standard ([basic.link]/6):
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.
In the OP's example, the block-scope declaration extern int a; fails to find a matching declaration with linkage, because the local declaration int a = 2; which has no linkage hides the global declaration int a = 1; which has external linkage. Therefore, extern int a; defaults to external linkage. Also see paragraph 7:
When a block scope declaration of an entity with linkage is not found to refer to some other declaration,
then that entity is a member of the innermost enclosing namespace. However such a declaration does not
introduce the member name in its namespace scope.
Therefore, extern int a; declares a as a member of the nearest enclosing namespace, which is the global namespace. This means it's the same entity as the previously declared global a, since both declare a variable with the same name in the same namespace with linkage. In other words, it gives you a way to refer to the global variable within the block.
This use of extern was inherited from C, but it is obscure even in C. Its use should generally be avoided in favour of ::a.

does c++ allows hoisting or is it compiler specific ? even if

So i was looking through various questions to prepare for my interview that's up tomorrow and came across extern keyword, i understand that extern keyword specifies to allocate memory for a variable which is part of another program(dont know where to use) but the real doubt is,
#include<iostream>
using std::cout;
int main()
{
extern int a;
cout<<a;
return 0;
}
int a=20;
output:
20
i wonder how this works? even if hoisting works in c++ , i know a bit of JS hoisting like even if the declaration of a as int a is done first and assignment is done later , the output is ought to be a value a garbage value....
For this block scope declaration
extern int a;
the compiler searches a previous declaration of the name a in the global namespace that to determine whether it has external or internal linkage. If the compiler does not find the previous declaration it thinks that the variable a refers to a variable defined in the global namespace with external linkage.
And indeed there is a definition of the variable in the global namespace
int a=20;
So the two declarations refer to the same object defined in the global namespace.
From the C++ 17 Standard (6.5 Program and linkage)
2 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:
and
6 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
there is a visible declaration of an entity with linkage having the
same name and type, ignoring entities declared outside the innermost
enclosing namespace scope, 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.
That is a declaration in a block scope with the storage class specifier extern does not define a new object. It refers to an object with the same name defined in the enclosing namespace with an internal or external linkage.

Variables with both 'extern' and 'inline' specifiers

I couldn't find any information on this topic neither from stackoverflow or elsewhere.
I know that extern can be used with namespace scope variables in header files to disambiguate a definition int foo; from a bare declaration extern int foo;. That is done to avoid breaking the one-definition-rule, in case multiple files #include this same header file.
In C++17, one can use constexpr inline foo; for globals, which should be better than the old way. One could also use extern inline const/constexpr foo;, both compile without errors, but I have no idea if the extern makes any difference semantically.
So when should one use extern inline with variables, if ever? What is the best practice in C++17?
Based on the wording here:
Inline const variables at namespace scope have external linkage by default (unlike the non-inline non-volatile const-qualified variables)
It seems that there is never any need to add extern to an inline const(expr) variable.
Sometimes a coder prefers to put a declaration first and a definition later. extern is used for this purpose. It can be applied to a declaration of an inline variable as well. But you will not see this in small projects.
extern only means that a declaration is not a definition:
extern int i; //declaration of i
int j; //declare and define j to be equal to zero
inline means that the variable is inline: it can be defined in a different translation unit (TU), as long as the definition is the same, and it must be defined in every TU where it is ODR-used.
inline int k; //declare and define k to be 0, can appear in multiple TUs
extern inline int h; //h is an inline variable but not defined
//it can be used to forward the definition
int f() { return h;}
int h = 10;
There's no sense by using extern with inline. I think it's strange. You'd be giving a definition for a variable that is marked as being defined elsewhere.
You're putting the variable in the translation unit with inline, then asking for the compiler to look for it in another translation unit with extern.

Extern declaration on an extern "C" global variable

In C and C++ if I want to use a global variable in other compilation units I will define the variable like:
int g_myVal = 0;
This allocates storage for the int.
In the header file I then declare the variable:
extern int g_myVal;
This informs the compiler that said symbol exists in some other compilation unit. It is then up to the linker to resolve the symbol.
However if I want the variable to be available with "C" linkage I must define the variable (allocate storage) like:
extern "C" int g_myVal = 0;
So how does one then differentiate between allocating storage and just informing the compiler that said symbol exists in another compilation unit?
Your confusion stems from the fact that extern and extern "C" do two different things.
About extern
extern on its own is a storage class specifier:
[C++11: 7.1.1/6]: The extern specifier can be applied only to the names of variables and functions. The extern specifier cannot be used in the declaration of class members or function parameters. For the linkage of a name declared with an extern specifier, see 3.5. [ Note: The extern keyword can also be used in explicit-instantiations and linkage-specifications, but it is not a storage-class-specifier in such contexts. —end note ]
About extern "C"
As that trailing note alludes to, there is another context in which you may use the extern keyword and that is as a linkage specifier:
[C++11: 7.5/2]: Linkage (3.5) between C++ and non-C++ code fragments can be achieved using a linkage-specification:
linkage-specification:
extern string-literal { declaration-seqopt }
extern string-literal declaration
C++ likes to re-use keywords.
Declarations vs definitions
Now, by default, a variable marked with a linkage specifier is a declaration rather than a definition, so in that sense it is as if you had also used the other meaning of extern:
[C++11: 7.5/7]: A declaration directly contained in a linkage-specification is treated as if it contains the extern specifier (7.1.1) for the purpose of determining the linkage of the declared name and whether it is a definition. Such a declaration shall not specify a storage class. [ Example:
extern "C" double f();
static double f(); // error
extern "C" int i; // declaration
extern "C" {
int i; // definition
}
extern "C" static void g(); // error
— end example ]
As you can see in the above example, it is still possible to either a declaration or a definition when you use a linkage specifier.
Here's another example of that:
// Everything in this block has C linkage
extern "C" {
// Declaration of g_myVal
extern int g_myVal;
// Definition of g_myVal2
int g_myVal2;
}
int main()
{
g_myVal2 = 5; // ok
g_myVal = 6; // not okay - linker error, symbol not found
}
Live demo
When you add an initialiser...
That all being said, the treatment of g_myVal as a declaration is overruled by your use of an initialiser, which forces the statement to be a definition:
[C++11: 7/8]: Syntactic components beyond those found in the general form of declaration are added to a function declaration to make a function-definition. An object declaration, however, is also a definition unless it contains the extern specifier and has no initializer (3.1). A definition causes the appropriate amount of storage to be reserved and any appropriate initialization (8.5) to be done.
I hope that this clarifies what is going on in your code with these differing meanings of extern.
In this case, putting the initializer = 0 changed the declaration to a definition, which is why storage is allocated here. (The same would have happened even with just plain extern.)

Under what circumstances can an extern variable be used in definition?

I am very very sorry. I didn't know my incomplete code attachment would create such a mess. I am very glad to see so many sincere helps.
This code will compile:
int myadd(int, int);
static int main_stat = 5;
int main()
{
int i, j;
main_stat = 13;
j = myadd(-1,7);
i = main_stat;
cout << j << i; // 3 and 13
return 0;
}
myadd.cpp
extern int main_stat = -3;
int myadd(int x,int y)
{
int t = main_stat;
t = x + y;
y = t +main_stat;
return y; // will return 3
}
See I defined and extern linking main_stat. Why is that legal? I thought you could only link and not define.
Is storage allocated in the stack frame of myadd function call? Global static are allocated on heap, I believe, right?
EDIT
I am sorry, but I think this time I will narrow down my questions:
From C++ Primer 4ed
An extern declaration may include an initializer (when combined
becomes definition) only if it appears outside a function.
I am clear about one-definition rule.
Q1. Which copy of main_stat does myadd(int,int) uses when it is called? The same copy as the main has, but with a different value (which I can test) ? Or does each function has its own static global copy?
Q2. Is memory allocated on the heap for these global static variables? I know many things are up to implementation, but isn't heap used for static variables?
Q3. I know the followings two are valid
extern int x; // means int x is defined elsewhere
extern int x = 3; // declared and defined
Why do we want the second one if we can just declare a static global variable within the namespace of myadd ? How does it make things clear like aschepler said?
All variable declarations with an initializer are also definitions;
that's an overriding rule. Regardless of extern. There are even
cases where you need an extern on a definition: you can only
instantiate a template using a variable which has external linkage. And
const variables have internal linkage by default, so you need
something like:
extern int const i = 42;
if you want to use it to instantiate a template<int const*>.
The following is a declaration and definition:
int x;
Adding extern says "make it a declaration only, please".
But when you are providing a value, the line has to be a definition, so the variable gets extern storage class and you just happen to be defining it right in place anyway:
extern int x = 3;
The linkage semantics are as they usually are for extern, and the storage location is just as it would be for a normal definition int x = 3 — i.e. in that TU at namespace scope. myadd is not relevant at all.
It's a hard one to "prove", because it's a case of "there's no rule against it".
Here's the best quote:
[n3290: 3.1/2]: A declaration is a definition unless it declares
a function without specifying the function’s body (8.4), it
contains the extern specifier (7.1.1) or a linkage-specification25 (7.5) and neither an initializer nor a
function-body, [..]
And some other pertinent information:
[n3290: 3.5/2]: 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 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.
[n3290: 3.5/12]: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 there is a visible declaration of an entity with
linkage having the same name and type, ignoring entities declared
outside the innermost enclosing namespace scope, 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. [..]
extern int main_stat=-3;
declares and defines main_stat, While:
extern int main_stat;
just declares the variable main_stat.
You can have as many declarations as you want but you can have only one Definition.
The keyword extern, indicates External Linkage. Without it main_stat would be static and have Internal linkage and you cannot not use main_stat from another translation unit.
Is storage allocated in the stack frame of myadd ?
No definitely not on the stackframe of add.
Where the memory is allocated is implementation defined but you have the assurance that the object will be alive throughout the duration of the program.
The question apparently stems from some misconception.
Some people believe that extern keyword always turns a definition into a non-defining declaration. This is simply not true.
The keyword extern simply gives the declared entity external linkage. It can be applied to declarations. It can be applied to definitions (and remember that definitions are declarations as well).
So, saying that one can't define an extern entity is absolutely incorrect. One can. There's no problem with that at all.
The confusion is usually caused by the fact that when you apply extern to a definition like
int x; // no initializer
that definition suddenly turns into a non-defining declaration. This is true, but this is is no more than a one-off quirk of extern keyword that has to be remembered. If you take a definition like
int x = 42;
then applying the extern keyword to it will still preserve it as a definition, i.e. no quirks in this case.
First, according to your comment, the file containing the main function has the definition static int main_stat = 10;. You should be aware that this is not the same variable as you defined in the file containing myadd because as static variable its scope is restricted to that file. Indeed, thanks to that static variable with the same name, main is not able to access the variable you defined in this file.
But that doesn't mean that either variable was created on the stack. Both are separate global variables, it's just that the variable main_stat in the file containing main (I'll call that file main file for short, and this one myadd file) is not available in any other file, while the variable main_stat you defined here can be accessed from any file which contains the declaration extern main_stat; (note: without initializer!). The main file cannot contain this declaration, however, because it would conflict with the static variable of the same name.
Note that giving an initializer makes your declaration of the variable a definition, that is, it's the same as if you had omitted the extern (note however that if a variable is declared constant, the extern may not be omitted because constants are by default static). The only global extern declarations which are not also definitions are those with extern, but without initializer.
Everyone else has covered this pretty well, but just to show the variants in one place:
int x; // #1
is a declaration and definition. The initial value of x is zero.
int x = 3; // #2
is a declaration and definition.
const int cx; // #3
is illegal in C++.
const int cx = 3; // #4
is a declaration and definition, but cx has internal linkage if this is its first declaration in the translation unit.
extern int x; // #5
is a declaration but NOT a definition. There must be a definition of x somewhere else in the program.
extern int x = 3; // #6
is a declaration and a definition. The extern is unnecessary, but makes things clear.
extern const int cx; // #7
is a declaration but NOT a definition. There must be a definition of cx somewhere else in the program.
extern const int cx = 3; // #8
is a declaration and a definition. The extern is needed unless the previous declaration above was already seen.