Включение iostream приводит к разным двоичным
Компиляция следующего кода
int main() {
return 0;
}
дает сборку
main:
xorl %eax, %eax
ret
https://gcc.godbolt.org/z/oQvRDd
Если теперь включен iostream
#include <iostream>
int main() {
return 0;
}
эта сборка создана.
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
Включена полная оптимизация (-O3). https://gcc.godbolt.org/z/EtrEX8
Может кто-то объяснить, почему включение неиспользуемого заголовка изменяет двоичный файл. Что такое _GLOBAL__sub_I_main:
Ответы
Ответ 1
Каждая единица перевода, включающая <iostream>
содержит копию объекта ios_base::Init
:
static ios_base::Init __ioinit;
Этот объект используется для инициализации стандартных потоков (std::cout
и его друзей). Этот метод называется Schwarz Counter, и он гарантирует, что стандартные потоки всегда инициализируются до их первого использования (при условии, что заголовок iostream
включен).
Эта функция _GLOBAL__sub_I_main
- это код, который компилятор генерирует для каждой единицы перевода, которая вызывает конструкторы глобальных объектов в этой единицы перевода, а также организует вызовы соответствующего деструктора, которые будут вызываться при выходе. Этот код вызывается кодом запуска стандартной библиотеки C++ до вызова main
.
Ответ 2
Включение заголовка iostream
приводит к добавлению определения статического объекта std::ios_base::Init
. Конструктор этого статического объекта инициализирует стандартные потоковые объекты std::cout
, std::cerr
и т.д.
Причина этого заключается в том, чтобы избежать фиаско порядка статического инициализации. Он обеспечивает правильную инициализацию объектов потока через единицы перевода.