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

Include of iostream leads to different binary

本文关键字:二进制文件 iostream 包含      更新时间:2023-10-16

编译以下代码

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 计数器,它确保标准流始终在首次使用之前进行初始化(前提是已包含iostream标头(。

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

包含iostream标头具有添加静态std::ios_base::Init对象定义的效果。此静态对象的构造函数初始化标准流对象std::coutstd::cerr等。

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