Demystifying C++ - Initialization of Global Variables
In C, the initialization of global variables is restricted to constant expressions. This means that all global variables must be initialized at compile time, and runtime calculations or functions cannot be used. In contrast, C++ allows for more flexible initialization. When global objects or variables in C++ are created that require non-constant initialization or have a constructor, the compiler generates a special initialization function (often referred to as "global constructor"). This function is automatically called at the start of the program, even before the main() function is invoked. The clang or gcc compiler allows the specification of global constructors using the function attribute __attribute__((constructor)).
Furthermore, the C++ compiler generates a special destructor function in the case of global objects with a destructor. This function is registered during the initialization of the global object using the "Itanium ABI" function __cxa_atexit
and is automatically called when the program ends normally (e.g., when return is called in the main() function or when exit() is invoked). Additionally, a DSO handle is passed to the function. DSO stands for Dynamic Shared Object, and it allows, for example, separate execution of all destructor functions for shared object (.so) files.
Examples for Global Variable Initialization
The following table shows C++ code and simplified equivalent C.
C++ Code | Equivalent C Code | |
---|---|---|
Initialization of Global Variable | double sqrt2 = sqrt(2.0); |
__attribute__((constructor)) static void __cxx_global_var_init_sqrt2(void) { sqrt2 = sqrt(2.0); } |
Global Variable with Constructor/Destructor | C1 obj; |
extern char __dso_handle; __attribute__((constructor)) static void __cxx_global_var_init_obj(void) { C1_ctor_complete(&obj); __cxa_atexit(&C1_dtor_complete, &obj, &__dso_handle); } |