次のコードをコンパイルする
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:
とは何ですか?
<iostream>
を含む各翻訳単位には、ios_base::Init
オブジェクトのコピーが含まれます。
static ios_base::Init __ioinit;
このオブジェクトは、標準ストリーム(std::cout
およびそのフレンド)を初期化するために使用されます。このメソッドは Schwarz Counter と呼ばれ、標準ストリームが最初に使用される前に必ず初期化されるようにします(iostream
ヘッダーが含まれている場合)。
その関数_GLOBAL__sub_I_main
は、翻訳ユニット内のグローバルオブジェクトのコンストラクターを呼び出す翻訳ユニットごとにコンパイラーが生成するコードであり、対応するデストラクター呼び出しが終了時に呼び出されるように調整します。このコードは、main
が呼び出される前にC++標準ライブラリの起動コードによって呼び出されます。
iostream
ヘッダーを含めると、静的std::ios_base::Init
オブジェクトの定義を追加する効果があります。この静的オブジェクトのコンストラクタは、標準ストリームオブジェクトstd::cout
、std::cerr
などを初期化します。
これが行われる理由は、静的な初期化順序の大失敗を避けるためです。これにより、翻訳オブジェクト間でストリームオブジェクトが適切に初期化されます。