【问题标题】:C++ global variable initialization orderC++ 全局变量初始化顺序
【发布时间】:2014-03-01 16:54:58
【问题描述】:

我不明白以下代码示例的作用以及它是如何做到的:

#include <stdio.h>

int f();

int a = f(); // a exists just to call f

int x = 22;

int f() {
    ++x;
    return 123; // unimportant arbitrary number
}

int main() {
    printf("%d\n", x);
}

运行时它会打印出23,这是直观的答案。

但是在 C++ 中,全局变量是按定义顺序初始化的 supposed to be。这意味着a 应该在x 之前初始化,因为它是在x 之前定义的。如果是这种情况,则必须在初始化 x 之前调用函数 f,因为对 f 的调用是 a 定义的一部分。

如果f 确实在x 初始化之前被调用,那意味着f 将尝试增加x——我不确定的结果(很可能是UB,或者一些乱码值)。然后,在a被初始化后,x会被初始化为22,程序会打印出22

显然不是这样。但有什么作用?该代码实际上做了什么?

在评估 a = f() 之前,x 似乎被设置为 22,但这意味着初始化的顺序是颠倒的(我也可能错了初始化是什么,或者什么时候发生) .

【问题讨论】:

    标签: c++ variables initialization declaration definition


    【解决方案1】:

    这个问题有点微妙;详情请参考C++11 3.6.2。

    对我们来说重要的是“具有静态存储持续时间的非局部变量”(或通俗的说法是“全局变量”)的初始化有两个阶段:静态初始化阶段动态初始化阶段。静态阶段首先出现。它看起来像这样:

    int a = 0;
    int x = 22;
    

    动态初始化之后运行:

    a = f();
    

    关键是静态初始化根本不会“运行”——它只包含在编译时已知的设置值,因此这些值在任何执行发生之前就已经设置好了。使初始化int x = 22; 静态的原因在于初始化程序是一个常量表达式。


    在某些情况下,动态初始化可能被提升到静态阶段(但不是必须),但这不是其中一种情况,因为它不满足要求 p>

    初始化的动态版本在初始化之前不会更改命名空间范围内的任何其他对象的值

    当这种提升发生时,产生的初始值可以与没有发生时不同。标准中有一个这样的“不确定”初始化示例。

    【讨论】:

    • 因此,从本质上讲,初始化分为首先“运行”的无副作用部分(没有函数,只是改变内存并增加堆栈指针的汇编代码),以及一个侧面-第二个运行的影响部分(其中执行实际功能)。如果一个函数可以被证明没有副作用,那么它可以被提升到第一部分。我理解正确吗?有道理。另外,您写了x = f();,但我认为您的意思是a = f();(这就是我的代码中的内容)。
    • 你最后一段的第一句话也有点奇怪:​​当这个提升发生时,产生的初始值可以与没有发生的不同。 i> - 你是什么意思?看起来你错过了一个“它”,但总的来说,你所描述的有点令人困惑,也许发布这个例子会有所帮助?
    • @yannbane:这个例子在我引用的部分。我不愿意开始复制其中的大部分内容,因为您基本上应该阅读所有内容。我推荐你head over to github 并为自己获取一份标准的副本。是的,有两个阶段。第一阶段甚至不“改变内存”——初始值只是写入二进制文件并由加载器加载到内存中。
    • @yannbane:我粘贴了示例on pastebin, here
    • @yannbane:我修正了错字,对此感到抱歉。
    【解决方案2】:

    另外,请考虑:

    #include <iostream>
    using namespace std;
    
    int f();
    int g();
    
    int a = f();
    int b = g();
    
    int main() {
            cout << a << " " << b;
    }
    
    int f() {
            b++;
            cout << "f" << endl;
            return 1;
    }
    
    int g() {
            cout << "g" << endl;
            return 2;
    }
    

    输出是:

    f
    g
    1 2
    

    b = g(); 替换为b = 22; 会导致打印1 23。 Kerrek SB 的回答解释了为什么会这样。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-12-20
      • 1970-01-01
      • 1970-01-01
      • 2020-08-15
      • 1970-01-01
      相关资源
      最近更新 更多