Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/138.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 静态初始化命令失败_C++_Initialization_Dependencies_Static Order Fiasco - Fatal编程技术网

C++ 静态初始化命令失败

C++ 静态初始化命令失败,c++,initialization,dependencies,static-order-fiasco,C++,Initialization,Dependencies,Static Order Fiasco,我从一本书中读到了关于SIOF的内容,它给出了一个例子: //file1.cpp extern int y; int x=y+1; //file2.cpp extern int x; int y=x+1; 现在我的问题是: 在上面的代码中,会发生以下事情吗 编译file1.cpp时,编译器保留y的原样,即不为其分配存储 编译器为x分配存储,但不初始化它 编译file2.cpp时,编译器保留x的原样,即不为其分配存储 编译器为y分配存储,但不初始化它 在链接file1.o和file2.o时

我从一本书中读到了关于SIOF的内容,它给出了一个例子:

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

//file2.cpp
extern int x;
int y=x+1;  
现在我的问题是:
在上面的代码中,会发生以下事情吗

  • 编译file1.cpp时,编译器保留y的原样,即不为其分配存储
  • 编译器为x分配存储,但不初始化它
  • 编译file2.cpp时,编译器保留x的原样,即不为其分配存储
  • 编译器为y分配存储,但不初始化它
  • 在链接file1.o和file2.o时,现在让file2.o先初始化,所以现在:
    x是否得到初始值0?或者没有初始化

  • 它依赖于编译器,也可能依赖于运行时。当访问文件中的第一个变量时,或者当访问每个变量时,编译器可能会决定延迟初始化静态变量。否则,它将在启动时通过文件初始化所有静态变量,其顺序通常取决于文件的链接顺序。文件顺序可能会根据依赖项或其他编译器相关影响而更改

    静态变量通常初始化为零,除非它们具有常量初始值设定项。同样,这取决于编译器。因此,当另一个变量初始化时,其中一个变量可能为零。但是,由于两者都有初始值设定项,一些编译器可能会保留未定义的值

    我认为最有可能的情况是:

  • 为变量分配了空间,两个变量的值均为0
  • 一个变量(如x)被初始化并设置为值1
  • 另一个,例如y,被初始化并设置为值2

  • 你可以随时运行它并查看。可能有些编译器会生成进入无限循环的代码。

    整个要点(以及被称为“惨败”的原因)是不可能确切地说在这种情况下会发生什么。本质上,你要求的是一些不可能的事情(两个变量各自大于另一个)。因为他们不能这样做,他们会做的是对一些问题——他们可能产生0/1,或1/0,或1/2,或2/1,或可能(最好的情况)只是一个错误消息。< /P> < P>初始化步骤在3.62.“初始化非本地对象”的C++标准:< /P> 第1步:
    x
    y
    在进行任何其他初始化之前初始化为零

    步骤2:
    x
    y
    动态初始化-标准未指定哪一个。该变量将获得值
    1
    ,因为另一个变量已初始化为零


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

    SIOF很大程度上是一个运行时工件,编译器和链接器与此无关。考虑ATEXIT()函数,它注册要在程序出口处调用的函数。许多CRT实现都有类似的程序初始化功能,我们称之为atinit()

    初始化这些全局变量需要执行代码,该值不能由编译器确定。因此,编译器生成执行表达式并赋值的机器代码片段。这些代码段需要在main()运行之前执行

    这就是它发挥作用的地方。一个常见的CRT实现遍历一系列atinit函数指针,并按顺序执行初始化代码段。问题在于函数在atinit()列表中的注册顺序。虽然atexit()有一个定义良好的后进先出顺序,并且它由代码调用atexit()的顺序隐式确定,但atinit函数的情况并非如此。语言规范不需要顺序,您无法在代码中指定顺序。SIOF是结果


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

    但我怀疑,如果编译器不为extern int y;分配存储;,那么它如何将其初始化为零呢?或者当y被初始化为零时?在编译时还是在链接时?初始化变量时有什么规则吗?你能一步一步地解释编译和链接时会发生什么情况吗?谢谢..但是在步骤1中,wll x和y何时初始化为零:编译时还是链接时?@Happy Mittal:你不知道,因此编译器可以选择。甚至可能是在程序加载时。