In "Programming principles and practice using C " by Stroustrup, it is recommended not using a lot of global objects especially those that depend on each other:
8.6.2 Global initialization
Global variables (and namespace variables; see §8.7) in a single translation unit are initialized in the order in which they appear. For example:
// file f1.cpp int x1 = 1; int y1 = x1 2; // y1 becomes 3
This initialization logically takes place "before the code in
main()
is executed."Using a global variable in anything but the most limited circumstances is usually not a good idea. We have mentioned the problem of the programmer having no really effective way of knowing which parts of a large program read and/or write a global variable (§8.4). Another problem is that the order of initialization of global variables in different translation units is not defined. For example:
// file f2.cpp extern int y1; int y2 = y1 2; // y2 becomes 2 or 5
Such code is to be avoided for several reasons: it uses global variables, it gives the global variables short names, and it uses complicated initialization of the global variables. If the globals in file
f1.cpp
are initialized before the globals inf2.cpp
,y2
will be initialized to5
(as a programmer might naively and reasonably expect).However, if the globals in file
f2.cpp
are initialized before the globals inf1.cpp
,y2
will be initialized to2
(because the memory used for global variables is initialized to0
before complicated initialization is attempted). Avoid such code, and be very suspicious when you see global variables with nontrivial initializers; consider any initializer that isn’t a constant expression complicated.
I think the problem in this example is called "Static Initialization Order Fiasco":
So if globals in
f2.cpp
are initialized before those inf1.cpp
theny2
has the value2
: does this mean this Undefined Behavior? or Implementation-defined Behavior?
"y2
will be initialized to 2
(because the memory used for global variables is initialized to 0
before complicated initialization is attempted) " but that memory hasn't been set aside yet so how could it be initialized to 0
? because control doesn't pass by the definition of globlas in file1.cpp
yet. So I think it is UB.
If I manually compile those files starting with
file1.cpp
thenfile2.cpp
then I link and run the program; Does the same problem of initialization persist? e.g:g -c file1.cpp g -c file2.cpp g -c main.cpp
Then:
g file1.o file2.o main.o -o prog
./prog
CodePudding user response:
It's neither.
When there is a finite set of possible outcomes, and the Standard does not require the implementation to document what happens, the result is known as Unspecified Behaior. In this case, "y2 becomes 2 or 5" clearly has two possible outcomes, and formatting your hard disk isn't on the list.
As for zero-initialization: remember that the Standard does not prescribe how an implementation achieves the required effect. Globals will be, or appear to be, initialized to 0. But remember that C is a compiled language. The compiler has seen your entire program before the program is started. It knows exactly which globals exist, and how big they are.
CodePudding user response:
Is static initialization order fiasco Undefined or Implementation-defined behavior?
It's implementation defined but can also be both. It may depend on the build system used and the order you're linking your compiled translation units together.
- If your implementation does not clearly state what happens when you deals it this hand - the behavior is undefined.
An implementation isn't always capable of sorting this out if you compile each translation unit separately (or even if you do compile them together).
The solution is to never supply your compiler/linker with this situation to sort out. Always make sure that there is no possible static initialization failure possible.