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

时间:2018-08-29 13:59:21

标签: c++ assembly iostream

编译以下代码

height = input

进行集会

int main() {
    return 0;
}

https://gcc.godbolt.org/z/oQvRDd

如果现在包含main: xorl %eax, %eax ret

iostream

此程序集已创建。

#include <iostream>   
int main() {
    return 0;
}

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

有人可以解释一下,为什么包括未使用的标头会更改二进制文件。什么是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

2 个答案:

答案 0 :(得分:33)

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

static ios_base::Init __ioinit;

此对象用于初始化标准流(std::cout及其朋友)。此方法称为Schwarz Counter,可确保始终在首次使用标准流之前初始化标准流(已提供iostream标头)。

该函数_GLOBAL__sub_I_main是编译器为每个翻译单元生成的代码,该代码调用该翻译单元中的全局对象的构造函数,并安排在出口处调用相应的析构函数调用。在调用main之前,C ++标准库启动代码将调用此代码。

答案 1 :(得分:23)

包含iostream标头的作用是添加静态std::ios_base::Init对象的定义。该静态对象的构造函数将初始化标准流对象std::coutstd::cerr等。

这样做的原因是避免静态初始化顺序的惨败。这样可以确保跨翻译单元正确地初始化流对象。