简体   繁体   中英

Where does the C++ standard say, and does C say the same: variables in a compilation unit (.cpp file) are initialised in order of declaration

Here it is states that

C++ guarantees that variables in a compilation unit (.cpp file) are initialized in order of declaration

Is this the same for C?

Can you quote the relevant standard passages for both C and C++?

Let's start with C. Asking this for C is like asking: If a tree falls in a forest and no one is around to hear it, does it make a sound? It doesn't matter because there is no way to write a valid C program that can tell the difference. This means that it would be pointless for the standard to define this. All we need to know is that by the time any code runs variables with static storage duration have been initialized. The C11 standard draft spells it out in section 5.1.2:

All objects with static storage duration shall be initialized (set to their initial values) before program startup. The manner and timing of such initialization are otherwise unspecified.

In C++ on the other hand, things aren't that easy. It is possible to observe the order of initialization during dynamic initialization. In the standard draft we find section 3.6.2. It quickly gets complicated. It defines the order as: first we do static initialization (this is equivalent to the only thing C can do) and after that dynamic initialization is done. So far so good. We get to this part:

Variables with ordered initialization defined within a single translation unit shall be initialized in the order of their definitions in the translation unit.

and everything is still ok in the world. But then things quickly fall apart:

An implementation is permitted to perform the initialization of a non-local variable with static storage duration as a static initialization even if such initialization is not required to be done statically

This sentence moves us from a predictable world to "it's complicated". The code example in that section of the standard explains this perfectly:

inline double fd() { return 1.0; }
extern double d1;
double d2 = d1;   // unspecified:
                  // may be statically initialized to 0.0 or
                  // dynamically initialized to 0.0 if d1 is
                  // dynamically initialized, or 1.0 otherwise
double d1 = fd(); // may be initialized statically or dynamically to 1.0

In short, in C it doesn't matter, in C++ if you write code that depends on this you'll quite likely to run into trouble when you change compilers.

So your quote is doubly incorrect. Not only isn't initialization done in order of declaration (it's static first, then dynamic), it's also quite fuzzy what is actually static and what is dynamic.

In C++ the order of initialisation has to be defined, since there may be constructors which are called in the initialisation of a variable. Thus C++ defines in which order this code is executed. In plain C there are no constructors. There is no way to tell in which order the variables are initialised, as long as each variable gets initialised before any code that can access the variable is executed.

The C standard (C11) 6.7.6 says

A full declarator is a declarator that is not part of another declarator. The end of a full declarator is a sequence point.

Meaning that at the end of each declaration, the initialization must be done and all sub-expressions must have been evaluated for side effects.

When the actual code is executed isn't specified. Meaning it could be done long before the line where the initialization takes place, but not after that line.

Variables with static storage duration is a special case, since they are guaranteed to be initialized before program startup. Their order of execution wouldn't matter in C, since they can't depend on each other (must be initialized to constant expressions).

In C++, class objects with static storage duration are initialized in an unspecified order and therefore they shouldn't be written so that they rely on each other to be initialized in a certain order.

Also please note 6.7.9/23:

The evaluations of the initialization list expressions are indeterminately sequenced with respect to one another and thus the order in which any side effects occur is unspecified.

Meaning that we can't know the order in which all initializers part of the same declaration are executed.

I believe C and C++ are identical in all of the above, though C++ will also execute constructors as part of the initialization.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM