This code compiles fine:
extern int i = 10;
void test()
{
std::cout << "Hi" << i << std::endl;
}
While this one gives an error:
void test()
{
extern int i = 10;
std::cout << "Hi" << i << std::endl;
}
error: 'i' has both 'extern' and initializer
I read in C++ Primer
Any declaration that includes an explicit initializer is a definition.
We can provide an initializer on a variable defined as extern, but
doing so overrides the extern. An extern that has an initializer is a
definition. It is an error to provide an initializer on an extern inside a
function.
Can someone provide an explanation why this should be an error if done locally in a function, while the same is allowed at a global scope?
The reason defining an external variable inside a function does not make sense is the following:
When you declare a symbol extern, you are telling the compiler to link all such occurrences of this value into the same symbol. Any occurences of extern int i; in your program would link to the externally defined i. Look at this example:
#include <iostream>
using namespace std;
extern int i;
int i = 10;
void test()
{
std::cout << "Hi" << i << std::endl;
}
int main()
{
extern int i;
i++;
test();
}
This example should output hi11. HOwever, if we remove the extern inside main, it will output 10. This is because without extern, i is not linking to the global i, but creating it's own local copy of i.
The reason that defining an extern i inside a function does not make sense, is what if we allowed any function to "define" i. Which function runs first? When does it get defined?
Assume the following example to be valid, what would the output be???
#include <iostream>
using namespace std;
extern int i;
int i = 10;
void test()
{
std::cout << "Hi" << i << std::endl;
}
void test2() {
extern int i = 1000;
std::cout<< "HI" << i << std::endl;
}
void test3() {
extern int i;
i = 1000;
std::cout<< "HI" << i << std::endl;
}
int main()
{
extern int i;
i++;
test();
i = 0;
test2();
}
Should the output of test2 be 0, or 1000? Also look at my test3, here we are concisely saying, link my i to the externally defined i, and assign it's value as 1000. This is very different from trying to "initialize" a value.
In short, extern variables really only make sense as globals, and should be defined in global scope. In your examples, the first version doesn't compile either for me. I find this interesting. It might be worth looking at the standards docs to see if this is defined concisely, or if your compiler might be handling this in a way designed to add additional protection...
By adding an initialiser to the declaration, it becomes a definition of the global variable. It's equivalent to the same definition without extern
, which is what your book means when it says it "overrides the extern".
While global variables can be declared (using extern
) inside a function, they cannot be defined there, only at namespace scope. That's why the second snippet is an error.
If you want to know why the designers of C (whence these rules came to C++) chose to allow declarations but not definitions here, then I'm afraid I don't know the language's history in enough detail to answer.
At first ,you should familiar with the conception of linkage and the meaning of extern linkage:
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.
--3.5.6.2 n3242
The function of static
which is differ from extern
,extern
is just a request,static
is a command.
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.
--3.5.6.6 n3242
Therefore,in block scope the procedure below is recommend to do:
extern int i;//declare it,request the linkage according to 3.5.6.6 above
i = 10;//modify it when has link to a defination
For the global extern declaration is possibly convert form
extern int i =10;
to
extern int i;//include in .hpp is recommended
int i =10;//global or namespace variable defination
The simplest way to put it:
The purpose of the extern
keyword is to declare an object without defining it. By defining it, you're basically telling the compiler "Do not assign a value but assign a value". That doesn't make sense - It should never be done, inside or outside a function. Most compilers will either warn you and proceed anyway, or they won't compiler at all and give an error.
Though it's beyond the scope of this question to explain in detail what extern
does, you may find it useful to read the answers for this question.
extern
variables are initialized before any function runs:
en.cppreference.com/w/cpp/language/initialization#Non-local_variables
If it was declared static
rather than extern
within a function block, it would still have static storage duration, but its' linkage would be local to that function vs. external. So it would be initialized when the execution first runs through that line within the function:
en.cppreference.com/w/cpp/language/storage_duration#Static_local_variables
So it's ok to initialize static
variables in a function block, but not ok to initialize extern
variables there.