Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C++ global variable initialization order

I don't understand what the following code example does and how it does it:

#include <stdio.h>  int f();  int a = f(); // a exists just to call f  int x = 22;  int f() {     ++x;     return 123; // unimportant arbitrary number }  int main() {     printf("%d\n", x); } 

When this is ran it prints 23, which is the intuitive answer.

However in C++, global variables are supposed to be initialized in order of definition. That would mean that a should be initialized before x, because it is defined before x. If that was the case, then the function f would have to be called before x was initialized, because the call to f is a part of a's definition.

If f is indeed called before x is initialized, that would mean that f would try to increment x -- the result of which I'm not really certain of (most likely UB, or some gibberish value). Then, after a is initialized, x would be initialized to 22 and the program would print out 22.

Evidently that's not what happens. But what does? What does that code actually do?

It definitely seems like x is set to 22 before a = f() is evaluated, but that would mean that the order of initialization is reversed (I could also be wrong about what initialization is, or when it happens).

like image 242
corazza Avatar asked Mar 01 '14 16:03

corazza


People also ask

In what order are global variables initialized?

Example# Whereas inside a Translation Unit, order of initialization of global variables is specified, order of initialization across Translation Units is unspecified. That may lead to Static Initialization Order Fiasco.

How are global variables initialized in C?

In C, static and global variables are initialized by the compiler itself. Therefore, they must be initialized with a constant value. Note that the above programs compile and run fine in C++, and produce the output as 10.

What is the order of initialization for data?

In the initializer list, the order of execution takes place according to the order of declaration of member variables. While using the initializer list for a class in C++, the order of declaration of member variables affects the output of the program. Program 1: C++

Are global variables automatically initialized to 0?

Global and static variables are initialized to their default values because it is in the C or C++ standards and it is free to assign a value by zero at compile time. Both static and global variable behave same to the generated object code.


2 Answers

The issue is a little bit subtle; please refer to C++11 3.6.2 for details.

What matters for us is that there are two phases of initialization of "non-local variables with static storage duration" (or "global variables" in colloquial parlance): the static initialization phase and the dynamic initialization phase. The static phase comes first. It looks like this:

int a = 0; int x = 22; 

The dynamic initialization runs afterwards:

a = f(); 

The point is that static initialization doesn't "run" at all - it only consists of setting values that are known at compile time, so those values are already set before any execution happens. What makes the initialization int x = 22; static is that the initializer is a constant expression.


There are cases where dynamic initialization may be hoisted to the static phase (but does not have to), but this is not one of those cases, because it does not meet the requirement that

the dynamic version of the initialization does not change the value of any other object of namespace scope prior to its initialization

When this hoisting happens, it is permissible that the resulting initial values can be different from if it didn't happen. There's an example in the standard for one such "indeterminate" initialization.

like image 153
Kerrek SB Avatar answered Oct 14 '22 11:10

Kerrek SB


Also, consider:

#include <iostream> using namespace std;  int f(); int g();  int a = f(); int b = g();  int main() {         cout << a << " " << b; }  int f() {         b++;         cout << "f" << endl;         return 1; }  int g() {         cout << "g" << endl;         return 2; } 

The output is:

f g 1 2 

Replacing b = g(); with b = 22; causes 1 23 to be printed. Kerrek SB's answer explains why this is.

like image 24
OSborn Avatar answered Oct 14 '22 10:10

OSborn