In the last lesson, you learned that variables declared inside a block have block scope. Block scope variables can only be accessed within the block in which they are declared (or a nested sub-block), and are destroyed when the block ends.
Variables declared outside of a block are called global variables. Global variables have program scope, which means they can be accessed everywhere in the program, and they are only destroyed when the program ends.
Here is an example of declaring a global variable:
int g_nX; // global variable
int main()
{
int nY; // local variable nY
// global vars can be seen everywhere in program
// so we can change their values here
g_nX = 5;
} // nY is destroyed here
Because global variables have program scope, they can be used across multiple files. In the section on programs with multiple files, you learned that in order to use a function declared in another file, you have to use a forward declaration, or a header file.
Similarly, in order to use a global variable that has been declared in another file, you have to use a forward declaration or a header file, along with the extern keyword. Extern tells the compiler that you are not declaring a new variable, but instead referring to a variable declared elsewhere.
Here is an example of using a forward declaration style extern:
global.cpp:
// declaration of g_nValue int g_nValue = 5;
main.cpp:
// extern tells the compiler this variable is declared elsewhere
extern int g_nValue;
int main()
{
g_nValue = 7;
return 0;
}
Here is an example of using a header file extern:
global.cpp:
// declaration of g_nValue int g_nValue = 5;
global.h:
#ifndef GLOBAL_H // header guards #define GLOBAL_H // extern tells the compiler this variable is declared elsewhere extern int g_nValue; #endif
main.cpp:
#include "global.h"
int main()
{
g_nValue = 7;
return 0;
}
Generally speaking, if a global variable is going to be used in more than 2 files, it’s better to use the header file approach. Some programmers place all of a programs global variables in a file called globals.cpp, and create a header file named globals.h to be included by other .cpp files that need to use them.
Local variables with the same name as a global variable hide the global variable inside that block. However, the global scope operator (::) can be used to tell the compiler you mean the global version:
int nValue = 5;
int main()
{
int nValue = 7; // hides the global nValue variable
nValue++; // increments local nValue, not global nValue
::nValue--; // decrements global nValue, not local nValue
return 0;
} // local nValue is destroyed
However, having local variables with the same name as global variables is usually a recipe for trouble, and should be avoided whenever possible. Using Hungarian Notation, it is common to declare global variables with a “g_” prefix. This is an easy way to differentiate global variable from local variables, and avoid variables being hidden due to naming collisions.
New programmers are often tempted to use lots of global variables, because they are easy to work with, especially when many functions are involved. However, this is a very bad idea. In fact, global variables should generally be avoided completely!
Why global variables are evil
Global variables should be avoided for several reasons, but the primary reason is because they increase your program’s complexity immensely. For example, say you were examining a program and you wanted to know what a variable named g_nValue was used for. Because g_nValue is a global, and globals can be used anywhere in the entire program, you’d have to examine every single line of every single file! In a computer program with hundreds of files and millions of lines of code, you can imagine how long this would take!
Second, global variables are dangerous because their values can be changed by any function that is called, and there is no easy way for the programmer to know that this will happen. Consider the following program:
// declare global variable
int g_nMode = 1;
void doSomething()
{
g_nMode = 2;
}
int main()
{
g_nMode = 1;
doSomething();
// Programmer expects g_nMode to be 1
// But doSomething changed it to 2!
if (g_nMode == 1)
cout << "No threat detected." << endl;
else
cout << "Launching nuclear missiles..." << endl;
return 0;
}
Note that the programmer set g_nMode to 1, and then called doSomething(). Unless the programmer had explicit knowledge that doSomething() was going to change the value of g_nMode, he or she was probably not expecting doSomething() to change the value! Consequently, the rest of main() doesn’t work like the programmer expects (and the world is obliterated).
Global variables make every function call potentially dangerous, and the programmer has no easy way of knowing which ones are dangerous and which ones aren’t! Local variables are much safer because other functions can not affect them directly. Consequently, global variables should not be used unless there is a very good reason!
4.3 — File scope and the static keyword
|
Index
|
4.1 — Blocks (compound statements) and local variables
|
4.3 — File scope and the static keyword
Index
4.1 — Blocks (compound statements) and local variables
Thanks that was great!
I was facing problem with global variable declaration and using it into mutiple files.
The problem is fixed.
How do I know if I have a really good reason? Can you give us an example from your experience where you decided you should use a global variable, please?
I honestly can’t think of the last time I used a global variable.
Typically, people use global variables for one of three reasons:
1) Because they don’t understand C++ variable passing mechanics, or they’re being lazy.
2) To hold data that needs to be used by the entire program (eg. configuration settings).
3) To pass data between code that doesn’t have a caller/callee relationship (eg. multi-threaded programs)
Obviously #1 isn’t a good reason at all. Once you get into C++ classes, there are better ways to do #2 (eg. static classes). That pretty much leaves #3, and maybe a few other cases I’m not aware of.
Basically, the only time you should use a global variable is if there is no practical way to do what you want using local variables and variable passing mechanics. In my opinion, use of globals should always be a last resort — so in a way, it’s a “you’ll know it when you run into it” situation, as there simply won’t be any other reasonable way to proceed.
“Launching nuclear missiles”, LOL. Evil globals; don’t trust ‘em.
Anyway, I just wanted to say that these tutorials are really good. Thanks. ;D