In the last lesson, you learned that variables declared inside a block are called local variables. Local variables have block scope (they are only visible within the block they are declared), and have automatic duration (they are created at the point of definition and destroyed when the block is exited).
Variables declared outside of a block are called global variables. Global variables have static duration, which means they are created when the program starts and are destroyed when it ends. Global variables have file scope (also informally called “global scope” or “global namespace scope”), which means they are visible until the end of the file in which they are declared.
Defining global variables
By convention, global variables are declared at the top of a file, below the includes, but above any code. Here’s an example of a couple of global variables being defined.
Similar to how variables in an inner block with the same name as a variable in an outer block hides the variable in the outer block, local variables with the same name as a global variable hide the global variable inside the block that the local variable is declared in. However, the global scope operator (::) can be used to tell the compiler you mean the global version instead of the local version.
This code prints:
However, having local variables with the same name as global variables is usually a recipe for trouble, and should be avoided whenever possible. By convention, many developers prefix global variable names with “g_” to indicate that they are global. This both helps identify global variables as well as avoids naming conflicts with local variables.
Internal and external linkage via the static and extern keywords
In addition to scope and duration, variables have a third property: linkage. A variable’s linkage determines whether multiple instances of an identifier refer to the same variable or not.
A variable with no linkage can only be referred to from the limited scope it exists in. Normal local variables are an example of variables with no linkage. Two local variables with the same name but defined in different functions have no linkage -- each will be considered an independent variable.
A variable with internal linkage is called an internal variable (or static variable). Variables with internal linkage can be used anywhere within the file they are defined in, but can not be referenced outside the file they exist in.
A variable with external linkage is called an external variable. Variables with external linkage can be used both in the file they are defined in, as well as in other files.
If we want to make a global variable internal (able to be used only within a single file), we can use the static keyword to do so:
Similarly, if we want to make a global variable external (able to be used anywhere in our program), we can use the extern keyword to do so:
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.
Variable forward declarations via the extern keyword
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 function forward declaration.
Similarly, in order to use an external global variable that has been declared in another file, you have to use a variable forward declaration. For variables, creating a forward declaration is also done via the extern keyword (with no initialization value).
Here is an example of using a variable forward declaration:
global.cpp:
main.cpp:
If the forward declaration is declared outside of a block, it applies for the whole file. If the forward declaration is declared inside a block, it applies within that block only.
If a variable is declared as static, trying to use a forward declaration to access it will not work:
constants.cpp:
main.cpp:
Note that if you want to define an uninitialized non-const global variable, do not use the extern keyword, otherwise C++ will think you’re trying to make a forward declaration for the variable.
Function linkage
Functions have the same linkage property that variables do. Functions always default to external linkage, but can be set to internal linkage via the static keyword:
Function forward declarations don’t need the extern keyword. The compiler is able to tell whether you’re defining a function or a function prototype by whether you supply a function body or not.
File scope vs. global scope
The terms “file scope” and “global scope” tend to cause confusion, and this is partly due to the way they are informally used. Technically, in C++, all global variables in C++ have “file scope”. However, informally, the term “file scope” is more often applied to file scope variables with internal linkage only, and “global scope” to file scope variables with external linkage.
Consider the following program:
global.cpp:
main.cpp:
g_x has file scope within global.cpp -- it can not be directly seen outside of global.cpp. Note that even though it’s used in main.cpp, main.cpp isn’t seeing g_x, it’s seeing the forward declaration of g_x (which also has file scope). The linker is responsible for linking up the definition of g_x in global.cpp with the use of g_x in main.cpp.
Global symbolic constants
In section 2.9 -- Symbolic constants and the const keyword, we introduced the concept of symbolic constants, and defined them like this:
constants.h:
While this is simple (and fine for smaller programs), every time constants.h gets #included into a different code file, each of these variables is copied into the including code file. Therefore, if constants.h gets included into 20 different code files, each of these variables is duplicated 20 times. Header guards won’t stop this from happening, as they only prevent a header from being included more than once into a single including file, not from being included one time into multiple different code files. This duplication of variables isn’t really that much of a problem (since constants aren’t likely to be huge), but changing a single constant value would require recompiling every file that includes the constants header, which can head to lengthy rebuild times for larger projects.
We can avoid this problem by turning these constants into const global variables, and changing the header file to hold only the variable forward declarations:
constants.cpp:
constants.h:
Use in the code file stays the same:
Now the symbolic constants will get instantiated only once (in constants.cpp), instead of once every time constants.h is #included, and the other uses will simply refer to the version in constants.cpp. Any changes made to constants.cpp will require recompiling only constants.cpp.
However, there is a downside to doing this: these constants are no longer considered compile-time constants, and thus can’t be used anywhere that requires a compile-time constant.
Because global symbolic constants should be namespaced and are read-only, the use of the g_ prefix is not necessary.
A word of caution about (non-const) global variables
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, use of non-const global variables should generally be avoided altogether! We’ll discuss why in the next section.
Summary
Global variables have global scope, and can be used anywhere in the program. Like functions, you must use a forward declaration (via keyword extern) to use a global variable defined in another file.
By default, non-const global variables have external linkage. You can use the static keyword to explicitly make them internal if desired.
By default, const global variables have internal linkage. You can use the extern keyword to explicitly make them external if desired.
By default, const global variables have internal linkage. You can use the extern keyword to explicitly make them external if desired.
Use a g_ prefix to help identify your non-const global variables.
Here’s a summary chart of the use of the extern and static keywords for non-const and const variable use cases:
Quiz
1) What’s the difference between a variable’s scope, duration, and linkage? What kind of scope, duration, and linkage do global variables have?
1) What’s the difference between a variable’s scope, duration, and linkage? What kind of scope, duration, and linkage do global variables have?
Quiz Solutions
Scope determines where a variable is accessible. Duration determines where a variable is created and destroyed. Linkage determines whether the variable can be exported to another file or not.
Global variables have global scope (aka. file scope), which means they can be accessed from the point of declaration to the end of the file in which they are declared.
Global variables have static duration, which means they are created when the program is started, and destroyed when it ends.
Global variables can have either internal or external linkage, via the static and extern keywords respectively.
No comments:
Post a Comment
whatiscpp.blogspot.com is a free website devoted to teaching you how to program in C++. Whether you’ve had any prior programming experience or not, the tutorials on this site will walk you through all the steps to write, compile, and debug your C++ programs, all with plenty of examples.