Search code examples
c++globalexternlinkage

Aren't non-const variable considered external by default?


Learning from this: By default, non-const variables declared outside of a block are assumed to be external. However, const variables declared outside of a block are assumed to be internal.

But if I write this inside MyTools.h:

#ifndef _TOOLSIPLUG_
#define _TOOLSIPLUG_

typedef struct {
    double LN20;
} S;

S tool;

#endif // !_TOOLSIPLUG_

and I include MyTools.h 3 times (from 3 different .cpp) it says that tool is already defined (at linker phase). Only if I change in:

extern S tool;

works. Isn't external default?


Solution

  • The declaration S tool; at namespace scope, does declare an extern linkage variable. It also defines it. And that's the problem, since you do that in three different translation units: you're saying to the linker that you have accidentally named three different global variables, of the same type, the same.


    One way to achieve the effect you seem to desire, a single global shared variable declared in the header, is to do this:

    inline auto tool_instance()
        -> S&
    {
        static S the_tool;    // One single instance shared in all units.
        return the_tool;
    }
    
    static S& tool = tool_instance();
    

    The function-accessing-a-local-static is called a Meyers' singleton, after Scott Meyers.

    In C++17 and later you can also just declare an inline variable.


    Note that global variables are considered Evil™. Quoting Wikipedia on that issue:

    The use of global variables makes software harder to read and understand. Since any code anywhere in the program can change the value of the variable at any time, understanding the use of the variable may entail understanding a large portion of the program. Global variables make separating code into reusable libraries more difficult. They can lead to problems of naming because a global variable defined in one file may conflict with the same name used for a global variable in another file (thus causing linking to fail). A local variable of the same name can shield the global variable from access, again leading to harder-to-understand code. The setting of a global variable can create side effects that are hard to locate and predict. The use of global variables makes it more difficult to isolate units of code for purposes of unit testing; thus they can directly contribute to lowering the quality of the code.

    Disclaimer: code not touched by compiler's hands.