C++ ordre d'initialisation des variables globales
je ne comprends pas ce que l'exemple de code suivant fait et comment il le fait:
#include <stdio.h>
int f();
int a = f(); // a exists just to call f
int x = 22;
int f() {
++x;
return 123; // unimportant arbitrary number
}
int main() {
printf("%dn", x);
}
Quand c'est couru d'estampes 23
, qui est la réponse intuitive.
Cependant en C++, Les variables globales sont censé être initialisé par ordre de définition. Cela voudrait dire que a
doit être initialisé avant x
, parce qu'il est défini à l'avant x
. Si c'était le cas, alors la fonction f
devrait être appelée avant x
a été initialisé, parce que l'appel à f
fait partie de a
définition.
Si f
est en effet appelé avant x
est initialisé, ce qui signifie que f
essayez d'incrémenter x
-- le résultat dont je ne suis pas vraiment certain (très probablement UB, ou une certaine valeur de charabia). Puis, après a
initialisation x
serait initialisé 22
et le programme d'imprimer 22
.
Évidemment, ce n'est pas ce qui se passe. Mais qu'est-ce? Quel est le code?
Il semble définitivement comme x
est réglé sur 22
avant a = f()
est évaluée, mais cela voudrait dire que l'ordre de l'initialisation est inversé (je pourrais aussi être tort sur l'initialisation, ou quand on arrive).
3 réponses
le problème est un peu subtil; référez-vous à C++11 3.6.2 pour plus de détails.
ce qui compte pour nous, c'est qu'il y a deux phases d'initialisation des "variables non locales avec durée de stockage statique" (ou "variables globales" dans le langage courant):statique de la phase d'initialisation et phase d'initialisation dynamique. La phase statique vient en premier. Il ressemble à ceci:
int a = 0;
int x = 22;
l'initialisation dynamique s'exécute ensuite:
a = f();
le fait est que l'initialisation statique ne "s'exécute" pas du tout - elle consiste uniquement à définir des valeurs qui sont connues au moment de la compilation, donc ces valeurs sont déjà définies avant toute exécution. Ce qui rend l'initialisation int x = 22;
statique, c'est que l'initialiseur, est une expression constante.
il y a des cas où l'initialisation dynamique être hissé à la phase statique (mais ne pas le faire), mais ce n'est pas l'un de ces cas, car il ne répond pas à l'exigence que
la version dynamique de l'initialisation ne change pas la valeur de tout autre objet de namespace scope avant son initialisation
lorsque ce levage se produit, il est permis que les valeurs initiales résultantes puissent être différentes de si ce n'est pas le cas. Il y a un exemple dans la norme pour une telle initialisation "indéterminée".
Aussi, pensez à:
#include <iostream>
using namespace std;
int f();
int g();
int a = f();
int b = g();
int main() {
cout << a << " " << b;
}
int f() {
b++;
cout << "f" << endl;
return 1;
}
int g() {
cout << "g" << endl;
return 2;
}
La sortie est:
f
g
1 2
Remplacer b = g();
b = 22;
1 23
pour être imprimé. La réponse de Kerrek SB explique pourquoi.
Vous pouvez toujours réécrire votre programme comme ceci:
#include <stdio.h>
int f(int x) {
++x;
return x;
}
int main() {
printf("%d\n", f(22));
}