Discussion: Going Global
Execute the code to understand the output and gain insights into global variables.
We'll cover the following
Run the code
Now, it’s time to execute the code and observe the output.
#include <iostream>int id;int main(){std::cout << id;}
Understanding the output
This puzzle looks similar to the Hack the Planet! puzzle; they both use the value of an uninitialized variable id
. However, this is not an undefined behavior, and the program prints 0
. Why is that?
Local vs. non-local variables
The difference is that the id
variables in the “Hack the Planet!” puzzle are local variables, which pop in and out of existence each time the functions are called. They’re said to have automatic storage duration. The id
in this puzzle, on the other hand, is a global variable. More precisely, id
is a non-local variable with static storage duration, that is, the lifetime of id
is the entire duration of the program.
Static initialization
Unlike variables with automatic storage duration, variables with static storage duration are initialized as a consequence of program initiation. In the simple case of an int
with no initializer, it’s zero-initialized. If id
had an initializer, for example, int id = 2;
, we would instead say that it was constant-initialized to 2
. The collective term for zero initialization and constant initialization is static initialization.
Why are variables with static storage duration and no initializer initialized to zero when variables with automatic storage duration are not? In the general case, initializing a variable isn’t free. Some code needs to exist to do said initialization. If, for instance, we define a local variable int id = 0;
in a function, most systems need to emit a bit of code to set it to zero every time that function is called. C++ cannot guarantee that this is free or of negligible cost, and the design goal of C++ is not to pay for what we don’t use. C++ doesn’t want to leave room for a more performant language to exist. So, if we decide to omit the initializer and just define int id;
, C++ won’t make you pay that price.
Another difference between local and non-local variables is their scope. A local variable can only be accessed in the block in which it’s defined. A non-local variable, on the other hand, can be accessed from anywhere in the file or, if declared in a header file, from anywhere in the entire program where that header can be included. So, if we omit the initializer for a local variable, we have perfect control over where it will be used next. We probably left it uninitialized because we’ll initialize it in the following line or two anyway. But if we omit the initializer for a non-local variable, it’s a lot harder to reason about who will access it next.
Compare non-local variables with static storage duration to local variables with automatic storage duration:
Cost of initialization | Scope | |
Non-local static | Once | The whole file/program |
Local automatic | Every time the block is entered | The block in which it’s defined |
It’s harder to control the usages of non-local variables with static storage duration, and initializing them is cheap, so C++ will do it automatically.
Example
Let’s look at the x86 architecture for an example. We said previously that we pay the price of initialization once, but in fact, we don’t pay it at all! When our program starts, it needs to allocate memory for things like the stack, the heap, the program code, and, importantly for us, global data. On systems like Linux and Windows, when we get fresh physical memory from the operating system, it’s filled with zeroes to prevent us from reading the memory of whichever program previously used the same memory page. The compiler/linker can group all uninitialized global variables in one section called .bss
. When the program starts and memory is allocated for the .bss
section, it’s already filled with zeroes. So, these variables are zero-initialized at zero cost!
The word static
has many uses in C++. Whether or not id
has a static
specifier doesn’t affect its static storage duration. Writing static int id;
instead of just int id;
for a global variable only gives it internal linkage; that is, it cannot be linked from other translation units (other .cpp
files). It has a static storage duration regardless.
Level up your interview prep. Join Educative to access 70+ hands-on prep courses.