C++ static initialization vs __attribute__((constr

2019-01-15 17:52发布

问题:

Example:

struct Foo { Foo() { printf("foo\n"); } };
static Foo foo;

__attribute__((constructor)) static void _bar() { printf("bar\n"); }

Is it deterministic wether foo or bar is printed first?

(I hope and would expect that constructors of static objects are always executed first but not sure and GCCs doc about the constructor attribute doesn't say anything about it.)

回答1:

foo will be printed first, as the objects are initialized in the order of their declarations. Run and see:

  • Ideone online demo

By the way, __attribute__((constructor)) is not Standard C++. It is GCC's extension. So the behavior of your program depends on how GCC has defined it. In short, it is implementation-defined, according to it foo is printed first.

The doc says,

The constructor attribute causes the function to be called automatically before execution enters main (). Similarly, the destructor attribute causes the function to be called automatically after main () has completed or exit () has been called. Functions with these attributes are useful for initializing data that will be used implicitly during the execution of the program.

You may provide an optional integer priority to control the order in which constructor and destructor functions are run. A constructor with a smaller priority number runs before a constructor with a larger priority number; the opposite relationship holds for destructors. So, if you have a constructor that allocates a resource and a destructor that deallocates the same resource, both functions typically have the same priority. The priorities for constructor and destructor functions are the same as those specified for namespace-scope C++ objects (see C++ Attributes).

I think the text in bold implies, the objects are initialized in the order of their declarations, as I said before, which is pretty much confirmed by online demo also.

I guess you would also like to read this:

  • 7.7 C++-Specific Variable, Function, and Type Attributes

If you want to control/alter the initialization order, you can use init_priority attribute, providing priority. Taken from the page:

Some_Class  A  __attribute__ ((init_priority (2000)));
Some_Class  B  __attribute__ ((init_priority (543)));

Here, B is initialized before A.



回答2:

It seems non-deterministic. I also had foo\nbar\n as the output of the example in my question when compiled with GCC. However, when compiled with LLVM/Clang, I get bar\nfoo\n.

But, as I'm not sure if this might be a bug in Clang, I filled a bug report here. Edit: I got an answer there and it seems to be really a bug in Clang which is not yet fixed. Not sure what to conclude from that. The expected and should-be behavior really is deterministic here, however, you can't depend on it as there is at least one major compiler (Clang) which does it wrong (or different than GCC, if we take that as the spec for __attribute__((constructor))).

Note that this can be really relevant and important in real world code. E.g. here is an example which seeds a random generator which fails with Clang.