Assume file_1.cpp
and file_2.cpp
are two files in one program. I encountered situation as follows:
// file_1.cpp
extern int y; // Line 1
int z = y 1; // Line 2
int main() {
cout << y << endl; // 2
cout << z << endl; // probably 1, sometimes 3
}
// file_2.cpp
int x = 1; // Line 3
int y = x 1; // Line 4
My understanding is that, when the execution constructs global variables before it enters main()
, depending on the optimization setting, there is a possibility that the global variables in file_1.cpp
are constructed prior to the global variables in file_2.cpp
. In such case, the value of y
is set to 0
when it is used to initialize z
, and thus cout << z << endl;
prints 1
. Line 4
will be executed when the global variables in file_2.cpp
are constructed before entering main()
, so we still have cout << y << endl;
printing out 2
.
My question: to my knowledge, extern int y;
is a declaration without definition (it does not allocate memory, it does not really create the object, it just introduces the name into the program). So, I would like to know what precisely happens at Line 1
/Line 2
(in case cout << z << endl;
prints out 1
). Is y
really being defined and initialized to 0
there? Or is that just an optimization behavior done by the compiler/linker such that (during the initialization of z
) whenever the token y
is seen, it is replaced by the value 0
?
If y
is really being defined (and initialized to 0
) at Line 1
/Line 2
, it confuses me because it contradicts to my understanding that extern int y;
is just a declaration, and in that case I wonder how compiler/linker avoid redefinition when Line 4
is executed later.
I know that in real program, the code above is what we should avoid, but I just really want to know its implementation.
CodePudding user response:
The situation you describe is known as "global initialization order fiasco".
When a program starts, the memory for all global variables is filled with 0s (that is, each byte is 0). In the next stage, constructors or initializations for all global variables are executed. The order of those initializations within each file is determined by the order of variables definitions in that file, but the order of files is arbitrary.
In your example, y
is initialized in file_2.cpp
. If initialization of the variables defined in file_1.cpp
is executed before file_2.cpp
, you get z==1
.
extern int y;
in line 1 is, indeed, unrelated to the initialization order - it just allows to access y
in file_1.cpp
.