web-dev-qa-db-fra.com

Ordre d'initialisation des variables globales C ++

Je ne comprends pas ce que fait l'exemple de code suivant 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("%d\n", x);
}

Lorsqu'il est exécuté, il affiche 23, Ce qui est la réponse intuitive.

Cependant en C++, les variables globales sont supposées être initialisées par ordre de définition. Cela signifierait que a devrait être initialisé avant x, car il est défini avant x. Si tel était le cas, la fonction f devrait être appelée avant l'initialisation de x, car l'appel à f fait partie de a la définition de.

Si f est en effet appelé avant l'initialisation de x, cela signifierait que f essaierait d'incrémenter x - le résultat dont je ne suis pas vraiment certain (UB le plus probable, ou une certaine valeur de charabia). Ensuite, après avoir initialisé a, x serait initialisé à 22 Et le programme imprimerait 22.

Évidemment, ce n'est pas ce qui se passe. Mais qu'est-ce que ça fait? Que fait réellement ce code?

Il semble définitivement que x est réglé sur 22 Avant que a = f() soit évalué, mais cela signifierait que l'ordre d'initialisation est inversé (je peux aussi me tromper sur l'initialisation est, ou quand cela se produit).

35
corazza

Le problème est un peu subtil; veuillez vous référer à 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 une durée de stockage statique" (ou "variables globales" en langage courant): la phase d'initialisation statique et la phase d'initialisation dynamique. La phase statique vient en premier. Cela 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 connues au moment de la compilation, de sorte que ces valeurs sont déjà définies avant toute exécution. Qu'est-ce qui fait l'initialisation int x = 22; statique est que l'initialiseur est une expression constante.


Il y a des cas où l'initialisation dynamique peut être hissée à la phase statique (mais n'est pas obligée), mais ce n'est pas un de ces cas, car cela ne répond pas à l'exigence que

la version dynamique de l'initialisation ne modifie pas la valeur de tout autre objet de portée d'espace de noms avant son initialisation

Lorsque ce levage se produit, il est permis que les valeurs initiales résultantes puissent être différentes de si cela ne s'est pas produit. Il y a un exemple dans la norme pour une telle initialisation "indéterminée".

34
Kerrek SB

Considérez également:

#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

Le remplacement de b = g(); par b = 22; Entraîne l'impression de 1 23. La réponse de Kerrek SB explique pourquoi.

4
OSborn