静态初始化命令fiasco

Hap*_*tal 20 c++ dependencies initialization static-order-fiasco

我正在读一本关于SIOF的书,它举了一个例子:

//file1.cpp
extern int y;
int x=y+1;

//file2.cpp
extern int x;
int y=x+1;  
Run Code Online (Sandbox Code Playgroud)

现在我的问题是:
在上面的代码中,会发生以下事情吗?

  1. 编译file1.cpp时,编译器保留原样,即不为它分配存储空间.
  2. 编译器为x分配存储空间,但不对其进行初始化.
  3. 编译file2.cpp时,编译器会保留x,即不为它分配存储空间.
  4. 编译器为y分配存储空间,但不对其进行初始化.
  5. 在链接file1.o和file2.o时,现在先让file2.o初始化,现在:
    x的初始值是否为0?或者没有初始化?

Mic*_*urr 12

初始化步骤在C++标准的3.6.2"非本地对象的初始化"中给出:

第1步:xy任何其他初始化发生之前被初始化为零.

第2步:xy动态初始化 - 标准未指定哪一个.该变量将获得该值,1因为另一个变量将被零初始化.

第3步:动态初始化另一个变量,获取值2.

  • @Happy Mittal:您无法分辨,因此编译器可能会选择.它甚至可能在程序加载时. (6认同)

Han*_*ant 11

SIOF非常类似于运行时工件,编译器和链接器与它没有多大关系.考虑atexit()函数,它注册要在程序出口处调用的函数.许多CRT实现具有类似于程序初始化的东西,让我们称之为atinit().

初始化这些全局变量需要执行代码,编译器无法确定该值.因此,编译器会生成执行表达式并分配值的机器代码片段.这些片段需要在main()运行之前执行.

这就是atinit()发挥作用的地方.常见的CRT实现按顺序遍历atinit函数指针列表并执行初始化片段.问题是函数在atinit()列表中的注册顺序.虽然atexit()具有定义良好的LIFO顺序,并且它由代码调用atexit()的顺序隐式确定,但atinit函数不是这种情况.语言规范不需要订单,您可以在代码中执行任何操作来指定订单.SIOF就是结果.

一种可能的实现是编译器在单独的部分中发出函数指针.链接器合并它们,生成atinit列表.如果编译器执行此操作,则初始化顺序将由链接目标文件的顺序决定.查看映射文件,如果编译器执行此操作,您应该看到atinit部分.它不会被称为atinit,但可能会出现某种带有"init"的名称.看一下调用main()的CRT源代码也应该给出见解.