作者:阿依古丽丹_736 | 来源:互联网 | 2022-12-06 12:18
编译以下代码
int main() {
return 0;
}
给大会
main:
xorl %eax, %eax
ret
https://gcc.godbolt.org/z/oQvRDd
如果现在iostream
包括在内
#include
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> Maxim Egorus..:
每个
包含的翻译单元都包含一个ios_base::Init
对象的副本:
static ios_base::Init __ioinit;
此对象用于初始化标准流(std::cout
及其朋友).此方法称为Schwarz Counter,它确保标准流在首次使用之前始终初始化(iostream
包括提供的标头).
该函数_GLOBAL__sub_I_main
是编译器为每个转换单元生成的代码,该转换单元调用该转换单元中的全局对象的构造函数,并且还安排在退出时调用相应的析构函数调用.调用此代码之前,C++标准库启动代码将调用此代码main
.
这就是为什么你应该在不需要引用cin,cout,cerr,wcin,wcout和wcerr的翻译单元中包含`
`和/或``而不是``.
初始化,并且(可能更重要的是)在正常终止之前刷新它们.
2> StoryTeller ..:
包括iostream
头部具有添加静态std::ios_base::Init
对象的定义的效果.此静态对象的构造函数初始化标准流对象std::cout
,std::cerr
依此类推.
它完成的原因是避免静态初始化命令惨败.它确保流对象在翻译单元之间正确初始化.
即使使用链接时优化,我也不认为编译器有足够的信息来理解`__ioinit`在不引用任何标准流的转换单元中是多余的.