First, lets have a look into the standard (C++14 [basic.start.init] 3.6.3/4):
It is implementation-defined whether the dynamic initialization of a non-local variable with static storage duration is done before the first statement of main. If the initialization is deferred to some point in time after the first statement of main, it shall occur before the first odr-use (3.2) of any function or variable defined in the same translation unit as the variable to be initialized.
The volatile
specifier means that the variable can be modified from an external source. However, when there is no guarantee when it is initialized, it might happen that the variable is modified externally and then dynamic initialization happens afterwards. Or does it work differently when the volatile keyword is there?
Here is an example of what I am talking about: in myfile.h
#ifndef MYFILE_H_
#define MYFILE_H_
int my_init ();
#endif /* MYFILE_H_ */
in myfile.cpp
#include <myfile.h>
#include <iostream>
int my_init () {
std::cout << "init" << std::endl;
return 1;
}
static volatile int my_var __attribute__((unused)) = my_init();
in main.cpp
#include <myfile.h>
#include <iostream>
int main() {
std::cout << "main" << std::endl;
// Let's assume first odr-use of my_var or my_init happens down here, maybe
// in a function from another translation unit.
return 0;
}
Just imagine my_init to be a function that sets my_var to a valid default state, just in case it won't be set externally to another valid state. Hence, there is a problem when my_var it is first modified externally, but then later set to the default state. Hence the question, when is my_var initialized. Just as the standard quote above suggests or does volatile
change the game?
If the initialization is deferred to some point in time after the first statement of main, it shall occur before the first odr-use (3.2) of any function or variable defined in the same translation unit as the variable to be initialized.
You say "can be modified from an external source". But any such modification would be an odr-use of a variable (the variable in fact) defined in the same translation unit.
Even more so external sources don't have access to a static variable at all unless you somewhere export the address or have functions for modifying it. Which both would be in the same translation unit. So again, init happens before use.
The only case I don't see covered is when you declare a variable volatile because the hardware will change it outside the control of the code, like a timer. But then you better initialize the hardware manually or know what your implementation does. The order of initialization will matter as well as when.