static initializers in c

Started by
18 comments, last by SeanMiddleditch 10 years, 2 months ago

It certainly exists in both.

C89:

If an object that has automatic storage duration is not initialized explicitly, its value is indeterminate. If an object that has static storage duration is not initialized explicitly, it is initialized implicitly as if every member that has arithmetic type were assigned 0 and every member that has pointer type were assigned a null pointer constant.

C99:

If an object that has automatic storage duration is not initialized explicitly, its value is indeterminate. If an object that has static storage duration is not initialized explicitly, then:
— if it has pointer type, it is initialized to a null pointer;
— if it has arithmetic type, it is initialized to (positive or unsigned) zero;
— if it is an aggregate, every member is initialized (recursively) according to these rules;
— if it is a union, the first named member is initialized (recursively) according to these rules.

The ordering requirement existed even back in the K&R book from 1978. I don't know if it was specified in the earlier compilers, but even if the ordering wasn't specified (in order within the file, each file in unspecified order) since that is the easiest way to process it that is the likely behavior.

Now with that in mind, just because you can doesn't mean you should. **DON'T RELY ON STATIC INITIALIZATION**. I have seen actual shipped games where the static initialization took over ten seconds. We wanted to beat the previous team owners into oblivion when we did the port. The previous team masked it by mandatory splash screens.

Well I chceked it

c:\mingw\bin\gcc main.c -std=c99

and it does not compile, so maybe this is not in c, though?

Post your exact error message and the relevant lines and surrounding code indicated by the actual error messages. The concept of static initialization is probably not the bug.

main.c :
int init() {}
int x = init();
int main() {return 0;}
>c:\mingw\bin\gcc main.c -std=c99
main.c:2: initializer element is not constant
ps. maybe i gave it a bad name "static initializers" but i didnt know how to name such static (global) space initialization thing like "int x = init();" so i called it here "static initializers" (maybe "static space initializers" would be better here
Advertisement

Actually, I don't think C allows for initialization of global variables by calling a function, despite what Bregma and others have said.

I guess we have all been programming in C++ for too long. :)

Álvaro is right.

ISO/IEC 9899 [6.7.8](4) All the expressions in an initializer for an object that has static storage duration shall be constant expressions or string literals.

Stephen M. Webb
Professional Free Software Developer

As to order between modules (.o files i link in mingw) isnt it maybe
dependant on command line order of this files passed tolinker..?


It might be, but there is no standard so you can't depend on it. Might be now, then change when you update the compiler for example. That's the problem with relying on undefined behaviour.


The order is unspecified. "Undefined" means something else.

Sure you are correct but out of curiosity, what is the difference?

If global variables are initialized in an unspecified order, they will be initialized, you just don't know in what order. If you write a program that invokes undefined behavior, all bets are off: You can't predict what will happen at all.

Here's a good description of undefined behavior: http://blog.regehr.org/archives/213

Sure you are correct but out of curiosity, what is the difference?


Undefined, unspecified and implementation-defined behavior

Sean Middleditch – Game Systems Engineer – Join my team!

Note that since the order of initialization is unspecified, and using an object before it is constructed in undefined, having code that is sensitive to order of initialization across translation units is usually (always?) undefined behavior.

Sure you are correct but out of curiosity, what is the difference?


Undefined, unspecified and implementation-defined behavior

3.4.4 1 unspecified behavior use of an unspecified value, or other behavior where this International Standard provides two or more possibilities and imposes no further requirements on which is chosen in any instance

How is the order of statics across translation units unspecified then? Does the standard provide one or more standard orders? I thought it was undefined across different translation units.

[EDIT] Actually after reading that link's definition of "undefined" I guess it does make some sense. I always thought "undefined" was anything that was not specified by the standard but if "undefined" requires non-portable or erroneous data or program constructs, "unspecified" I guess covers everything else that is undefined but not erroneous. I suppose "undefined" is where even the compiler makes no guarantee of what will happen, regardless of standard and "unspecified" is where the compiler is doing something predictable and deterministic but not something the standard enforces.

Yeah, undefined behavior means your code is not C++, as defined by the C++ standard.

Undefined behavior has also been called "catch fire semantics" to underscore the fact that anything can happen, even your computer going ablaze, when undefined behavior is invoked.

How is the order of statics across translation units unspecified then? Does the standard provide one or more standard orders?


Yes, the standard does provide one or more possible orderings. The options available to the implementation are all of the ordering permutations of the translation units. Initializing all the statics of A.obj before B.obj is just as valid as doing B.obj before A.obj. The standard guarantees that they're all linked together and their statics will be initialized in some order. How that order is determined is not specified by the standard and each implementation is free to order them however it wants, even differently between successive runs.

If the implementation were expected to order TU initialization in a self-consistent manner then the behavior would be implementation-defined instead of unspecified. This is not a requirement the standard wanted to place on implementations. The implementation may not even be in control of the choice such as in a multi-threaded linker (so the statics initialized first are dependent on whichever translation unit's worker thread happened to be scheduled by the OS to run first). If the standard wanted to place restrictions on the implementation so that you the user could predict the initialization order on every conforming implementation (even if it differed between implementations), the standard would have made this behavior implementation-defined and whole classes of possible compilation optimizations would be illegal.

If the behavior were undefined behavior then that would mean that the TUs' static objects may be initialized in some order clearly documented by the implementation, or the implementation can elect to initialize only some of them and not document how it makes that choice, or all of them may be left uninitialized, or they all might be initialized to the same value as one of them, or the implementation may raise an error and abort upon seeing any static initializations, or the implementation could happily generate code that causes a CPU exception. Every implementation could do something different and none of them would be considered buggy in terms of standards compliance. Undefined behavior has a beneficial purpose in places but certainly not for static initialization ordering.

Sean Middleditch – Game Systems Engineer – Join my team!

This topic is closed to new replies.

Advertisement