Global variables are fraught with peril. Even moreso when those variables are in header files.
It's easier to explain in purposes of functions.
Say for example your program has two functions with identical names and signatures, in two separate cpp files.
EXHIBIT A:
1 2 3 4 5 6
|
// file1.cpp
void func()
{
cout << "file1.cpp";
}
|
1 2 3 4 5 6 7 8 9 10 11
|
// file2.cpp
void func()
{
cout << "file2.cpp";
}
int main()
{
func(); // which 'func' does this call?
}
|
The problem here is that the linker sees two separate 'func' functions, so when you call func from main, it has no idea which function it's supposed to actually call. The file1 version or the file2 version?
The exact same problem occurs with variables.
EXHIBIT B:
1 2 3
|
//file1.cpp
int glb = 0;
|
1 2 3 4 5 6 7 8
|
//file2.cpp
int glb = 0;
int main()
{
glb = 5; // which 'glb' are you setting? file1's or file2's?
}
|
This will give you the same linker error as exhibit A because you now have two externally visible variables named 'glb' and the linker gets confused as to which one of those two you actually want to use and where.
Now to expand this to what you're doing... you're putting a global variable in a header and including it in multiple cpp files. But this also does not work (as you're seeing).
EXHIBIT C:
1 2 3
|
//header.h
int glb = 0;
|
1 2
|
//file1.cpp
#include "header.h"
|
1 2 3 4 5 6 7
|
//file2.cpp
#include "header.h"
int main()
{
glb = 5; // SAME PROBLEM. See below
}
|
You might look at this and only see one 'glb' variable, but that's not what the linker sees. It still sees two. Giving you the same error as before.
What you have to remember is that #include is just a glorified copy/paste operation. When you include that header, the compiler will effectively drop the header file right into the cpp file. Giving you the
exact same scenario as Exhibit B: both cpp files are creating their own variable. And therefore the exact same problem: the linker gets confused on which variable to use.
So how do you solve this?
The best way is to simply not use globals. Ever. (well okay there are some situations where they're handy, but it's not nearly as often as you'd think). Globals generally are messy and make your program hard to manage. Get in the habit of objectifying things, and/or passing them between functions as parameters, and other more typical techniques.
If you insist on using globals (booo)... read on:
[Partially] Solving by creating only one global variable.
EXHIBIT D:
1 2
|
// file1.cpp
int glb = 0; // the one and only global variable
|
1 2 3 4 5 6
|
// file2.cpp
int main()
{
glb = 5; // not quite ok... but closer!
}
|
It's true that this code will work for
the linker when it tries to combine all your compiled source files together. There is only one glb variable defined so it's clear which variable your program wants to use. However this won't even get to the linker because
the compiler (which only ever sees one cpp file at a time) sees that 'glb' and doesn't know what the hell it is because it wasn't declared in this cpp file.
So now you'd get a compiler error about glb being undefined.
So how can we tell the compiler that a variable exists without actually creating it? The answer is the
extern
keyword.
EXHIBIT E:
1 2
|
//file1.cpp
int glb = 0; // the one and only global variable
|
1 2 3 4 5 6 7
|
//file2.cpp
extern int glb; // tell the compiler is exists somewhere else, just not in this file
int main()
{
glb = 5; //NO PROBLEMO
}
|
Or... more traditionally, you would put the extern declaration in the header, and the actual variable definition in one and only one cpp file.
EXHIBIT F:
1 2
|
//header.h
extern int glb;
|
1 2 3 4
|
//file1.cpp
#include "header.h" // strictly, this isn't necessary here... but it doesn't hurt.
int glb = 0; // the one and only variable
|
1 2 3 4 5 6 7
|
//file2.cpp
#include "header.h"
int main()
{
glb = 5; // NO PROBLEMO - header.h has the extern declaration so we're all good.
}
|
If this is confusing... it might help to equate to how functions work. Remember that you cannot have two different function bodies... just like you can't have two different variables. Functions have the way to prototype them so you can use them without actually having to give them a body... and variables can be declared as extern which is basically the same thing.
EXHIBIT G:
1 2 3 4 5 6 7 8 9 10 11 12 13 14
|
void func(); // a function prototype. Tells the compiler the function exists
// without actually giving it a body.
extern int glb; // a variable prototype. Tells the compiler a variable exists without
// actually giving it a body. Exact same idea.
/***********/
void func()
{
// a function body. Can only have one of these for this function in your program
}
int glb; // a global variable. Can only have one of these for this var in your program.
|