Compilation du code suivant
int main() {
return 0;
}
donne l'Assemblée
main:
xorl %eax, %eax
ret
https://gcc.godbolt.org/z/oQvRDd
Si maintenant iostream
est inclus
#include <iostream>
int main() {
return 0;
}
cette Assemblée est créée.
main:
xorl %eax, %eax
ret
_GLOBAL__sub_I_main:
subq $8, %rsp
movl $_ZStL8__ioinit, %edi
call std::ios_base::Init::Init() [complete object constructor]
movl $__dso_handle, %edx
movl $_ZStL8__ioinit, %esi
movl $_ZNSt8ios_base4InitD1Ev, %edi
addq $8, %rsp
jmp __cxa_atexit
L'optimisation complète est activée (-O3). https://gcc.godbolt.org/z/EtrEX8
Quelqu'un peut-il expliquer pourquoi l'inclusion d'un en-tête inutilisé modifie le binaire. Quel est _GLOBAL__sub_I_main:
?
Chaque unité de traduction qui comprend <iostream>
contient une copie de ios_base::Init
objet:
static ios_base::Init __ioinit;
Cet objet est utilisé pour initialiser les flux standard (std::cout
et ses amis). Cette méthode est appelée Schwarz Counter et elle garantit que les flux standard sont toujours initialisés avant leur première utilisation (à condition que l'en-tête iostream
ait été inclus).
Cette fonction _GLOBAL__sub_I_main
est le code que le compilateur génère pour chaque unité de traduction qui appelle les constructeurs d'objets globaux dans cette unité de traduction et organise également l'appel des destructeurs correspondant à la sortie. Ce code est appelé par le code de démarrage de la bibliothèque standard C++ avant l'appel de main
.
L'inclusion de l'en-tête iostream
a pour effet d'ajouter la définition d'un objet statique std::ios_base::Init
. Le constructeur de cet objet statique initialise les objets de flux standard std::cout
, std::cerr
Et ainsi de suite.
La raison pour laquelle cela est fait est d'éviter le fiasco de l'ordre d'initialisation statique. Il garantit que les objets de flux sont correctement initialisés dans les unités de traduction.