Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

extern, linkage and global variables

Tags:

c++

In C++, say we have this header file:

myglobals.h

#ifndef my_globals_h
#define my_globals_h

int monthsInYear = 12;

#endif

and we include it in multiple implementation files, then we will get compilation errors since we end up with 'monthsInYear' defined multiple times, once in each file that monthsInYear is included in.

Fine. So if we modify our header and make our global const, like so:

const int monthsInYear = 12;

then our compilation errors go away. The explanation for this, as I understand it, and as given here for example, is that the const keyword here changes the linkage of monthsInYear to internal, which means that now each compilation unit that includes the header now has its own copy of the variable with internal linkage, hence we no longer have multiple definitions.

Now, an alternative would be to merely declare the variable in the header with extern, i.e.:

extern int monthsInYear;

and then define it in one of the implementation files that includes the header, i.e.:

#include "myglobals.h"
...
int monthsInYear = 12;
...

and then everywhere that includes it is dealing with one variable with external linkage.

This is fine, but the thing I'm a bit puzzled by is that using const gives it internal linkage, which fixes the problem, and using extern gives it external linkage, which also fixes the problem! It's like saying that any linkage will do, as long as we specify it. On top of that, when we just wrote:

int monthsInYear = 12;

wasn't the linkage already external? Which is why adding 'const' changed the linkage to internal?

It seems to me that the reason using 'extern' here actually fixes the problem isn't because it gives us external linkage (we already had that) but rather because it allows us to merely declare the variable without defining it, which we otherwise wouldn't be able to do, since:

int monthsInYear = 12;

both declares and defines it, and since including the header effectively copy-pastes the code into the implemenation file we end up with multiple definitions. Conversely, since extern allows us to merely declare it we end up with multiple declarations every time we include the header, which is fine since we're allowed to have multiple declarations, just not multiple definitions.

Is my understanding here correct? Sorry if this is massively obvious, but it seems that extern does at least three things:

  • specifies external linkage
  • allows declaration of objects without defining them
  • specifies static storage duration

but a lot of sources I look at don't make this clear, and when talking about using extern to stop 'multiple definition' errors with global variables don't make it clear that the key thing is separating the declaration from the definition.

like image 889
lemondifficult Avatar asked Jul 28 '15 04:07

lemondifficult


1 Answers

For a non-const variable, extern has the effect of specifying that the variable has external linkage (which is the default), but it also converts the definition into a declaration if there's no initializer - i.e. extern int i; does not actually define i. (extern int i = 5; would, and would hopefully generate a compiler warning).

When you write extern int monthsInYear; in multiple source files (or #include it into them, which is equivalent), none of them define it. int monthsInYear = 12; defines the variable in that source file only.

like image 53
user253751 Avatar answered Nov 15 '22 20:11

user253751