Global variable initialisation in C++ – 2021-11-18 22:00 (last update: 2022-01-02 22:50)

An ag(e)ing hacker — Luca Saiu's blog

Global variable initialisation in C++

Today Volker Birk and I were speaking over lunch about object initialisation in C++ and about how weakly defined a program entry point is, because of objects with static storage duration.

Volker wrote a short program whose output changes after reversing the order of two variable definitions, both out of a main function whose entire body was return 0;. He discussed it in German, on his blog.

I was more annoyed by the fact that initialisation order is not guaranteed to respect functional dependency across compilation units. Here is my test case, where GCC and the GNU linker exhibit the counter-intuitive (but conformant) behaviour.

Let us define a simple class foo with a non-default constructor logging initialisation to stdout, in a header named h.hh:

#include <iostream>

class foo
  int x;
  foo (int x_)
    : x (x_)
    std::cout << "Initializing a foo at " << this << "\n";
    std::cout << "its field will be " << x << "\n";

This file uses a foo variable f1 defined elsewhere to initialise another foo variable f2; here it would appear reasonable to assume that the current compilation unit could see f1 as already completely initialised, with an extern declaration:

#include <iostream>

#include "h.hh"

extern foo f1;
foo f2 = f1.x + 1;

main ()
  std::cout << f2.x << "\n";
  return 0;

The defiition of f1 is in this file,

#include "h.hh"

foo f1 = 4;

And now we can play around by referencing the two files in different orders on the command line of the compiler driver.

Here I am passing before

g++ -O3 && ./a.out

...which yields the intuitive behaviour: f1 is indeed initialised before f2.

Initializing a foo at 0x55cbc03b9194
its field will be 4
Initializing a foo at 0x55cbc03b919c
its field will be 5

However it is easy to observe a different behaviour:

g++ -O3 && ./a.out

By changing the order of the two files here we can see the f1 field set to zero when f2 is initialised — f1’s constructor running after f2’s:

Initializing a foo at 0x565447237194
its field will be 1
Initializing a foo at 0x56544723719c
its field will be 4

We were surprised to discover, after consulting the Standard (see §3.6.2 in n3797.pdf, p.59 near the bottom and then the next page) that in fact this preliminary zero-initialisation is guaranteed1 to happen before the actaual static or dynamic initialisation:

§3.6.2, point 2: Variables with static storage duration (3.7.1) or thread storage duration (3.7.2) shall be zero-initialized (8.5) before any other initialization takes place.

Notice that the behaviour of GCC and GNU ld is indeed conformant:

§3.6.2, point 2 [my emphasys]: If a program starts a thread (30.3), the subsequent initialization of a variable is unsequenced with respect to the initialization of a variable defined in a different translation unit. Otherwise, the initialization of a variable is indeterminately sequenced with respect to the initialization of a variable defined in a different translation unit.

This happens with every GCC version I have tested, from version 4 to version 11. I only tried on x86_64 and MIPS, but there is no reason to expect a different behaviour on other architectures.

In defence of the Standard I have to concede that the alternative of providing guarantees about initialisation order without failing at link or initialisation time is not realistic: it would be very easy to build a cycle of two variables mutually depending on each other for initialisation, across two compilation units.

— Luca Saiu, 2021-11-18 22:00 (last update: 2022-01-02 22:50)

c++, english, free-software, gcc, gnu, myself, p≡p

Next post Previous post

Go to the main index...
Atom feed All post feeds: Atom 1.0, RSS 2.0.

[my photo]
Luca Saiu

The opinions I express here are my own and do not necessarily reflect the beliefs or policies of my employer, or for that matter of anyone else. In case you felt that the public statement of my thoughts threatened your warm sense of security and your emotional stability, please feel free to leave at any time.

The system does not support user comments and probably never will. Anyway you can contact me by e-mail if you want to discuss some topic with me. I might update my posts if you provide interesting insights.

Copyright © 2009, 2011-2014, 2017, 2018, 2021, 2022 Luca Saiu
Verbatim copying and redistribution of this entire page are permitted in any medium without royalties, provided this notice is preserved.
This page was generated by trivialblog. trivialblog is free software, available under the GNU GPL.
Tag icon copyright information is available in this file.



Within the limits of as-if semantics, of course. But the behaviour is easily observable.