c++declarationdefinitionextern

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


This code compiles fine:

extern int i = 10;

void test()
{
    std::cout << "Hi" << i << std::endl;
}

While this code gives an error:

void test()
{
    extern int i = 10;
    std::cout << "Hi" << i << std::endl;
}

error: 'i' has both 'extern' and initializer

I read this 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 as to why this is an error if done locally in a function, while the same is allowed at a global scope?


Solution

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