markzzz
markzzz

Reputation: 47945

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?

Upvotes: 2

Views: 1329

Answers (3)

Pete Becker
Pete Becker

Reputation: 76315

There's a difference between a declaration and a definition. extern int i; is a declaration: it says that there's a variable named i whose type is int, and extern implies that it will be defined somewhere else. int i;, on the other hand, is a definition of the variable i. When you write a definition, it tells the compiler to create that variable. If you have definitions of the same variable in more than one source file, you've got multiple definitions, and the compiler (well, in practice, the linker) should complain. That's why putting the definition S tool; in the header creates problems: each source file that #include's that header ends up defining tool, and the compiler rightly complains.

The difference between a const and a not-const definition is, as you say, that const int i = 3; defines a variable named i that is local to the file being compiled. There's no problem having the same definition in more than one source file, because those guys all have internal linkage, that is, they aren't visible outside the source file. When you don't have the const, for example, with int i = 3;, that also defines a variable named i, but it has external linkage, that it, it's visible outside the source file, and having the same definition in multiple files gives you that error. (technically, it's definitions of the same name that lead to problems; int i = 3; and double i = 3.0; in two different source files still are duplicate definitions).

Upvotes: 3

Cheers and hth. - Alf
Cheers and hth. - Alf

Reputation: 145279

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.

Upvotes: 5

tdao
tdao

Reputation: 17668

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.

That statement is still correct in your case.

In your MyTools.h, tool is external.

S tool; // define tool, external scope

In your cpp file, however, the extern keyword merely means that S is defined else where.

extern S tool; // declare tool

Upvotes: 2

Related Questions