2014-03-01 280 views
33

我不明白下面的代码示例做什么以及它是如何做的:C++全局变量初始化顺序

#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之前定义。如果是这种情况,那么函数f必须在x初始化之前调用,因为f的调用是a的定义的一部分。

如果fx初始化之前确实叫,这将意味着f将设法增加x - 其结果我真的不特定的(最有可能UB,或一些乱码值)。然后,a初始化后,x将被初始化为22,程序将打印出22

很明显,这不是什么情况。但是,什么?代码实际上做了什么?

它肯定好像x设置为22a = f()前计算,但是这将意味着初始化的顺序是相反的(我也可能是错的什么初始化,或者当它发生)。

回答

33

这个问题有点微妙;有关详细信息,请参阅C++ 11 3.6.2。

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

int a = 0; 
int x = 22; 

动态初始化之后运行:

a = f(); 

的一点是,静态初始化不“跑”在所有 - 它仅由设置,在已知值编译时间,所以这些值在执行任何执行之前就已经设置好了。什么使初始化int x = 22;静态是初始化器是一个常量表达式。


在有些情况下动态初始化可以被提升到静止期(但并不一定)的情况下,但这不是这些案件之一,因为它不符合要求,即

初始化的动态版本不到其初始化

当这种情况发生吊装之前改变命名空间范围的任何其他对象的值,则允许如果没有发生,最终的初始值可能会不同。标准中有一个这样的“不确定”初始化的例子。

+0

所以基本上,初始化分为非副作用的一部分“运行”第一(无功能,只是汇编代码改变了内存并增加堆栈指针)以及第二个运行的副作用部分(在其中执行实际功能)。如果一个功能可以被证明没有副作用,那么它可以被升高到第一部分。我理解正确吗?有道理。另外,你写了'x = f();',但我认为你的意思是'a = f();'(这就是我的代码)。 – corazza

+0

另外,你最后一段的第一句话有点奇怪:*当这种提升发生时,最终的初始值可能会不同,如果它没有发生。* - 你是什么意思?看起来你错过了一个“它”,但总的来说,你所描述的有点混乱,也许发布这个例子会有所帮助? – corazza

+1

@yannbane:这个例子在我引用的部分。我不愿意开始复制它的大部分内容,因为你应该基本阅读它的全部内容。我建议你[转向github](https://github.com/cplusplus/draft),并为自己制作一份标准副本。是的,有两个阶段。第一阶段甚至不会“改变内存” - 初始值只是写入二进制文件并由加载程序加载到内存中。 –

4

另外,考虑:

#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的回答解释了这是为什么。

-5

您可以随时改写你的程序,因为这:

#include <stdio.h> 

int f(int x) { 
    ++x; 
    return x; 
} 

int main() { 
    printf("%d\n", f(22)); 
} 
+0

很抱歉,由于'a = f()'的原因,您的示例不会编译为C++代码。 – blackbird

+0

@blackbird然后我会修改它。 –

+0

现在这是一个很好的函数调用,但这里的主题是全局变量的初始化,并且你已经摆脱了所有这些变量:) – blackbird