Why Does Initializing an Extern Variable Inside a Function Give an Error

Why does initializing an extern variable inside a function give an error?

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...

Why does providing an explicit initializer on an extern inside a function not override extern?

According to C++ Primer, we can provide an initializer on a variable defined as extern, but doing so overrides the extern.

Only partially.

Providing an initializer forces the declaration to be a definition (except in the case of some static members of classes). It thus partially counteracts the effect of extern, which usually suppresses definition. However, extern can have other effects, and the initializer doesn't nullify those.

It is also stated in the book that providing an initializer on an extern inside a function is an error.

Yes. At block scope, extern is used to force a declaration to have external or internal linkage (rather than declaring a local variable). However, the language prohibits defining such a variable in a local scope. You can only declare it there, and provide a matching definition at namespace scope. If you provide an initializer, then you're trying to define the variable there, which is not allowed.

If providing an initializer on an extern outside any function can override the extern, why can providing it on an extern inside a function not?

As I explained, this premise is false. The initializer, in both cases, makes the declaration into a definition. In both cases, it does not override the fact that extern affects the linkage of the entity being declared.

I also don't understand why someone would want to both obtain a declaration adding the extern keyword and provide an initializer. Is it not the same as defining a variable and providing an initializer on it? If it is not, why?

When we use extern together with an initializer, it is usually because we are trying to define a const object with external linkage. See below:

// At global scope:
const int c1 = 42; // definition with internal linkage
extern const int c2; // declaration with external linkage
extern const int c3 = 42; // definition with external linkage

error in extern initialization with C++ compiler

One explanation of external:

The extern keyword tells the compiler that a variable is declared in another source module (outside of the current scope). The linker then finds this actual declaration and sets up the extern variable to point to the correct location. Variables described by extern statements will not have any space allocated for them, as they should be properly defined elsewhere. If a variable is declared extern, and the linker finds no actual declaration of it, it will throw an "Unresolved external symbol" error.

Since it’s declared elsewhere, that elsewhere is the place to initialize it.

More briefly, if you’re declaring it in a single-file program, that’s enough; drop the external phrase.

Use case for initialized extern variable

The extern specifier is useful in conjunction with variables that would have internal linkage without it, such as constants at namespace scope:

a.cpp:

extern const int n = 10;  // external linkage

b.cpp:

int main()
{
extern const int n; // finds the n defined in the other TU
return n;
}

Compilation Error for extern variable initialized in other file

You have to link against a.c while compiling b.c:

gcc a.c b.c

You can't expect the linker to magically find the C file where b is defined. extern means it is defined elsewhere - you have to say where. By compiling and linking with a.c, the linker can now find a declaration for b.

Of course, you can't have 2 main() functions.

Why isn't my extern variable initialized yet?

You can't (in a consistent manner)

But you can work around it.

global.cpp

// If you have a global variable that has to be initial by a constructor
MyObj globalX;

// Instead do this

MyObj& globalX() { static MyObj x; return x;}

You still have a global variable. But by putting it in a function we know when it is being used. By using a static member of the function it is initialized the first time the function is called but not after that. Thus you know that it will be correctly constructed before first use.



Related Topics



Leave a reply



Submit