web-dev-qa-db-fra.com

Quand les variables statiques et globales sont-elles initialisées?

Dans C++, je sais que les objets static et global sont construits avant la fonction main. Mais comme vous le savez, dans C, il n’existe pas de ce type initialization procedure avant main.

Par exemple, dans mon code:

int global_int1 = 5;
int global_int2;
static int static_int1 = 4;
static int static_int2;
  • Quand ces quatre variables initialisées ?
  • Où les valeurs d'initialisation telles que 5 et 4 sont-elles stockées lors de la compilation? Comment les gérer lors de l'initialisation?

MODIFIER:
Clarification de la 2ème question. 

  • Dans mon code, j'utilise 5 pour initialize global_int1, alors comment le compilateur peut-il affecter 5 à global_int? Par exemple, peut-être que le compilateur stocke d’abord la valeur 5 quelque part (c’est-à-dire une table) et obtient cette valeur au début de l’initialisation.
  • Quant à "Comment les gérer lors de l’initialisation?", C’est vraiment flou et je ne m’interprète pas encore. Parfois, il n'est pas facile d'expliquer une question. Oubliez cela car je n'ai pas encore complètement maîtrisé la question.
28
Zachary

Par objets statiques et globaux, je suppose que vous entendez des objets avec une durée de vie statique définie au niveau de l'espace de noms. Lorsque de tels objets Sont définis avec une portée locale, les règles sont légèrement différentes. 

Formellement, C++ initialise ces variables en trois phases: 1. Initialisation à zéro 2. Initialisation statique 3. Initialisation dynamique Le langage distingue également les variables qui requièrent une initialisation dynamique .__ et celles qui nécessitent une initialisation statique : Tous les objets statiques (objets avec static Life) sont d'abord initialisés à zéro, puis Les initialisations .__ sont initialisées, puis l’initialisation dynamique se produit.

En première approximation simple, l’initialisation dynamique signifie Qu’un code doit être exécuté; En règle générale, l'initialisation statique ne le fait pas. Ainsi:

extern int f();

int g1 = 42;    //  static initialization
int g2 = f();   //  dynamic initialization

Une autre approximation serait que l’initialisation statique soit Ce que C supporte (pour les variables à durée de vie statique), dynamique Tout le reste.

La manière dont le compilateur fait cela dépend, bien sûr, de l’initialisation , Mais sur les systèmes basés sur disque, où l’exécutable est chargé en mémoire à partir du disque, les valeurs pour l’initialisation disque et chargé directement par le système à partir du disque. Sur un système Unix Classique, les variables globales seraient divisées en trois "segments":

texte:
Le code, chargé dans une zone protégée en écriture. Les variables statiques Avec les types `const` seraient également placées ici .
les données:
Variables statiques avec initialiseurs statiques .
bss:
Variables statiques sans initialisation (C et C++) ou avec initialisation dynamique .__ (C++). L'exécutable ne contient aucune image pour ce segment Le système règle simplement le tout à 0 avant le À partir de votre code .

Je pense que beaucoup de systèmes modernes utilisent encore quelque chose de similaire.

MODIFIER: 

Une remarque supplémentaire: ce qui précède fait référence à C++ 03. Pour les programmes Existants, C++ 11 ne change probablement rien, mais il modifie Add constexpr (ce qui signifie que certaines fonctions définies par l'utilisateur Peuvent toujours être une initialisation statique) et les variables locales thread,. .qui ouvre une nouvelle boîte de Pandore.

21
James Kanze

Préface: Le mot "statique" a un grand nombre de significations différentes en C++. Ne vous trompez pas.

Tous vos objets ont durée de stockage statique . C'est parce qu'ils ne sont ni automatiques ni dynamiques. (Ni thread-local, bien que thread-local soit un peu statique).

En C++, les objets statiques sont initialisés en deux phases: initialisation statique et initialisation dynamique.

  • L’initialisation dynamique nécessite l’exécution du code, ce qui est le cas pour les objets commençant par un appel du constructeur ou pour lesquels l’initialiseur est une expression qui ne peut être évaluée qu’au moment de l’exécution.

  • L'initialisation statique survient lorsque l'initialiseur est connu de manière statique et qu'aucun constructeur n'a besoin de s'exécuter. (L'initialisation statique est soit zéro-initialisation ou constante-initialisation .) C'est le cas de vos variables int avec initialiseur constant, et vous êtes assuré que celles-ci sont bien initialisées dans la phase statique.

  • (Les variables de stockage statique avec initialisation dynamique sont aussi zéro-initialzées statiquement avant que quoi que ce soit ne se produise.)

Le point crucial est que la phase d’initialisation statique ne fonctionne pas du tout. Les données sont là dès le début. Cela signifie qu'il n'y a pas de "commande" ou de toute autre propriété dynamique de ce type concernant l'initialisation statique. Les valeurs initiales sont codées en dur dans votre programme binaire, si vous voulez.

12
Kerrek SB

Quand ces quatre variables sont-elles initialisées?

Comme vous le dites, cela se produit avant le démarrage du programme, c’est-à-dire avant que main ne commence. C ne le précise pas davantage; en C++, cela se produit pendant la phase d'initialisation static avant les objets avec des constructeurs ou des initialiseurs plus compliqués.

Où les valeurs pour l'initialisation comme 5 et 4 sont-elles stockées lors de la compilation?

En règle générale, les valeurs non nulles sont stockées dans un segment de données du fichier programme, tandis que les valeurs nulles se trouvent dans un segment bss qui réserve juste assez de mémoire pour les variables. Lorsque le programme démarre, le segment de données est chargé en mémoire et le segment bss est défini sur zéro. (Bien sûr, le standard de langage ne le spécifie pas, un compilateur peut donc faire autre chose, comme générer du code pour initialiser chaque variable avant d'exécuter main).

3
Mike Seymour

Paraphrasé de la norme:

Toutes les variables qui n'ont pas de durée de stockage dynamique, n'ont pas de durée de stockage local de thread et ne sont pas locales ont une durée de stockage statique. En d'autres termes, tous les globals ont une durée de stockage statique.

Les objets statiques avec initialisation dynamique ne sont pas nécessairement créés avant la première instruction de la fonction principale. Son implémentation est définie selon que ces objets sont créés avant la première instruction dans main ou avant la première utilisation d'une fonction ou d'une variable définie dans la même unité de traduction que la variable statique à initialiser. 

Ainsi, dans votre code, global_int1 et static_int1 sont définitivement initialisés avant la première instruction de main car ils sont initialisés de manière statique. Cependant, global_int2 et static_int2 étant initialisés de manière dynamique, leur initialisation est définie par la règle de mise en œuvre définie ci-dessus.

En ce qui concerne votre deuxième point, je ne suis pas sûr de comprendre ce que vous voulez dire. Pourriez-vous clarifier?

1
scl