包含 iostream 会导致不同的二进制文件

Include of iostream leads to different binary

编译以下代码

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    , %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    , %rsp
        jmp     __cxa_atexit

已开启全面优化 (-O3)。 https://gcc.godbolt.org/z/EtrEX8

有人可以解释一下,为什么包含未使用的 header 会更改二进制文件。什么是 _GLOBAL__sub_I_main:

包括iostreamheader的作用是添加一个static的定义std::ios_base::Initobject。此静态 object 的构造函数初始化标准流 objects std::coutstd::cerr 等等。

这样做的原因是为了避免静态初始化顺序的失败。它确保流 object 跨翻译单元正确初始化。

包含 <iostream> 的每个翻译单元都包含 ios_base::Init object 的副本:

static ios_base::Init __ioinit;

此 object 用于初始化标准流(std::cout 及其朋友)。此方法称为 Schwarz Counter,它确保标准流在首次使用之前始终被初始化(前提是已包含 iostream header)。

那个函数 _GLOBAL__sub_I_main 是编译器为每个翻译单元生成的代码,它调用该翻译单元中全局 object 的构造函数,并安排在退出时调用相应的析构函数.此代码在调用 main 之前由 C++ 标准库 start-up 代码调用。