Ready to practice?
Sign up to access interactive coding exercises and track your progress.
Working with Global Variables
Declare variables accessible from any function and understand their initialization order.
Introduction to Global Variables
In the Local variables lesson, we covered that local variables are variables defined inside a function body. Local variables have block scope (are only visible within the block they are declared in), and have automatic duration (they are created at the point of definition and destroyed when the block exits).
In C++, variables can also be declared outside of any function. Such variables are called global variables.
Declaring global variables
By convention, global variables are declared at the top of a file, below the includes, in the global namespace. Here's an example of a global variable being defined:
#include <iostream>
// Variables declared outside of any function are global variables
int g_counter{}; // global variable g_counter
void incrementCounter()
{
// global variables can be seen and used everywhere in the file
g_counter = 5;
std::cout << g_counter << '\n';
}
int main()
{
incrementCounter();
std::cout << g_counter << '\n';
// global variables can be seen and used everywhere in the file
g_counter = 12;
std::cout << g_counter << '\n';
return 0;
}
// g_counter goes out of scope here
The above example prints:
5 5 12
The scope of global variables
Identifiers declared in the global namespace have global namespace scope (commonly called global scope, and sometimes informally called file scope), which means they are visible from the point of declaration until the end of the file in which they are declared.
Once declared, a global variable can be used anywhere in the file from that point onward. In the above example, global variable g_counter is used in both functions incrementCounter() and main().
Global variables can also be defined inside a user-defined namespace. Here is the same example as above, but g_counter has been moved from the global scope into user-defined namespace Stats:
#include <iostream>
namespace Stats // Stats is defined in the global scope
{
int g_counter{}; // g_counter is now inside the Stats namespace, but is still a global variable
}
void incrementCounter()
{
// global variables can be seen and used everywhere in the file
Stats::g_counter = 5;
std::cout << Stats::g_counter << '\n';
}
int main()
{
incrementCounter();
std::cout << Stats::g_counter << '\n';
// global variables can be seen and used everywhere in the file
Stats::g_counter = 12;
std::cout << Stats::g_counter << '\n';
return 0;
}
Although the identifier g_counter is now limited to the scope of namespace Stats, that name is still globally accessible (via Stats::g_counter), and g_counter is still a global variable.
Variables declared inside a namespace are also global variables.
Prefer defining global variables inside a namespace rather than in the global namespace.
Global variables have static duration
Global variables are created when the program starts (before main() begins execution), and destroyed when it ends. This is called static duration. Variables with static duration are sometimes called static variables.
Naming global variables
By convention, some developers prefix global variable identifiers with "g" or "g_" to indicate that they are global. This prefix serves several purposes:
- It helps avoid naming collisions with other identifiers in the global namespace.
- It helps prevent inadvertent name shadowing (we discuss this point further in the Variable shadowing lesson).
- It helps indicate that the prefixed variables persist beyond the scope of the function, and thus any changes we make to them will also persist.
Global variables defined inside a user-defined namespace often omit the prefix (since the first two points in the list above are not an issue in this case, and we can infer that a variable is global when we see a prepended namespace name). However, it doesn't hurt to keep the prefix as a more visible reminder of the third point.
Consider using a "g" or "g\_" prefix when naming global variables (especially those defined in the global namespace), to help differentiate them from local variables and function parameters.
We sometimes get feedback from readers asking whether prefixes such as `g_` are okay because they've been told that prefixes are a form of [Hungarian notation](https://en.wikipedia.org/wiki/Hungarian_notation) and "Hungarian notation is bad".
The objection to Hungarian notation comes mainly from the use of Hungarian notation to encode the type of the variable in the variable's name. e.g., strName, where str means string. That's not particularly useful in modern C++.
However, using prefixes (typically g/g_, s/s_, and m/m_) to represent the scope or duration of a variable does add value, for the reasons noted in this section.
Global variable initialization
Unlike local variables, which are uninitialized by default, variables with static duration are zero-initialized by default.
Non-constant global variables can be optionally initialized:
int g_counter; // no explicit initializer (zero-initialized by default)
int g_total{}; // value initialized (resulting in zero-initialization)
int g_score{100}; // list initialized with specific value
Constant global variables
Just like local variables, global variables can be constant. As with all constants, constant global variables must be initialized.
#include <iostream>
const int g_limit; // error: constant variables must be initialized
constexpr int g_capacity; // error: constexpr variables must be initialized
const int g_maxUsers{50}; // const global variable g_maxUsers, initialized with a value
constexpr int g_maxConnections{100}; // constexpr global variable g_maxConnections, initialized with a value
void displayInfo()
{
// global variables can be seen and used everywhere in the file
std::cout << g_maxUsers << '\n';
std::cout << g_maxConnections << '\n';
}
int main()
{
displayInfo();
// global variables can be seen and used everywhere in the file
std::cout << g_maxUsers << '\n';
std::cout << g_maxConnections << '\n';
return 0;
}
// g_maxUsers and g_maxConnections go out of scope here
Advanced note: We discuss global constants in more detail in the Sharing global constants across multiple files lesson.
A word of caution about (non-constant) global variables
New programmers are often tempted to use lots of global variables, because they can be accessed without having to explicitly pass them to every function that needs them. However, use of non-constant global variables should generally be avoided altogether. We'll discuss why in the upcoming lesson on why non-const global variables are evil.
Summary
Global variables: Variables declared outside of any function, with global namespace scope, static duration, and either internal or external linkage depending on how they're declared.
Global namespace scope: Global variables are visible from their point of declaration until the end of the file. Variables declared inside namespaces are also global variables.
Static duration: Global variables are created when the program starts (before main()) and destroyed when it ends. This differs from local variables which have automatic duration.
Initialization: Non-constant global variables are zero-initialized by default if no explicit initializer is provided. Constant global variables must be initialized.
Naming convention: Consider prefixing global variables with "g" or "g_" to distinguish them from local variables and to indicate their persistence across function calls.
Internal vs external linkage: Non-const global variables have external linkage by default. Const and constexpr global variables have internal linkage by default.
Global variables provide a way to share data across functions, but non-const global variables should be used sparingly due to the issues we'll explore in later lessons. Const global variables, particularly those defined in namespaces, are generally safe and useful for application-wide constants.
Working with Global Variables - Quiz
Test your understanding of the lesson.
Practice Exercises
Global Variables Basics
Understand global variable scope and lifetime, and see how they differ from local variables.
Lesson Discussion
Share your thoughts and questions
No comments yet. Be the first to share your thoughts!