假设我有一个非常简单的程序,如下所示:
#include <iostream>
int main()
{
return 12;
}
当用gcc(从gcc-4.x到gcc-12.x)编译这个程序时,生成的代码是这样的(在编译器资源管理器上查看在线):
main:
push rbp
mov rbp, rsp
mov eax, 12
pop rbp
ret
__static_initialization_and_destruction_0(int, int):
push rbp
mov rbp, rsp
sub rsp, 16
mov DWORD PTR [rbp-4], edi
mov DWORD PTR [rbp-8], esi
cmp DWORD PTR [rbp-4], 1
jne .L5
cmp DWORD PTR [rbp-8], 65535
jne .L5
mov edi, OFFSET FLAT:_ZStL8__ioinit
call std::ios_base::Init::Init() [complete object constructor]
mov edx, OFFSET FLAT:__dso_handle
mov esi, OFFSET FLAT:_ZStL8__ioinit
mov edi, OFFSET FLAT:_ZNSt8ios_base4InitD1Ev
call __cxa_atexit
.L5:
nop
leave
ret
_GLOBAL__sub_I_main:
push rbp
mov rbp, rsp
mov esi, 65535
mov edi, 1
call __static_initialization_and_destruction_0(int, int)
pop rbp
ret
这是可以接受的,因为
<iostream>
头文件包含 ios_base::Init
对象的静态变量(有关更多信息,请参阅 此 Q/A)。
但是从 gcc-13.1 开始,包含
<iostream>
标头似乎对生成的代码没有影响。那么,问题是,gcc-13.1 是如何做到这一点的呢?是由于 iostream
头文件发生了变化吗?还是gcc在13.1版本的优化?
来自cppreference:
标头的行为就像它定义(直接或间接)具有静态存储持续时间的 std::ios_base::Init 实例一样:这使得可以安全地访问具有有序静态对象的构造函数和析构函数中的标准 I/O 流初始化(只要在定义这些对象之前包含在翻译单元中)。
这里最重要的是“好像”。
我没有检查标准措辞,但通常 cppreference 相当接近和可靠。