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.
Related
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.
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.
Is this program well-formed according to the c++ standard?
namespace X { int i = 1; }
using namespace X;
int main() {
extern int i;
i = 2;
}
I get different results with different compilers:
GCC and Clang gives a linker error: Undefined reference to i.
Visual c++ accepts the program.
[basic.link]/p6:
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.
X::i was declared outside the innermost enclosing namespace of the extern declaration (i.e the global namespace) so it is ignored. This means no declaration was found for i and therefore extern int i is a declaration of a new variable named i with external linkage.
Your program will compile, but will not link if the block-scope i is odr-used.
What part of the standard describes how entity does determine for the declared name? For instance
int foo(){ return 1; }
int main()
{
int foo(); //I know that this foo denotes the "global" foo.
}
How it's occuring?
In the C++11 standard, section 3.5p6 states
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.
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.