C++全局变量初始化顺序
我不明白下面的代码示例做什么以及它是如何做的: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
的定义的一部分。
如果f
x
初始化之前确实叫,这将意味着f
将设法增加x
- 其结果我真的不特定的(最有可能UB,或一些乱码值)。然后,a
初始化后,x
将被初始化为22
,程序将打印出22
。
很明显,这不是什么情况。但是,什么?代码实际上做了什么?
它肯定好像x
设置为22
a = f()
前计算,但是这将意味着初始化的顺序是相反的(我也可能是错的什么初始化,或者当它发生)。
这个问题有点微妙;有关详细信息,请参阅C++ 11 3.6.2。
对我们来说重要的是,有“非本地变量与静态存储时间”(或通俗的说法“全局变量”)的初始化两个阶段:静态初始化阶段和动态初始化阶段。静态阶段首先出现。它看起来像这样:
int a = 0;
int x = 22;
动态初始化之后运行:
a = f();
的一点是,静态初始化不“跑”在所有 - 它仅由设置,在已知值编译时间,所以这些值在执行任何执行之前就已经设置好了。什么使初始化int x = 22;
静态是初始化器是一个常量表达式。
在有些情况下动态初始化可以被提升到静止期(但并不一定)的情况下,但这不是这些案件之一,因为它不符合要求,即
初始化的动态版本不到其初始化
当这种情况发生吊装之前改变命名空间范围的任何其他对象的值,则允许如果没有发生,最终的初始值可能会不同。标准中有一个这样的“不确定”初始化的例子。
另外,考虑:
#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的回答解释了这是为什么。
所以基本上,初始化分为非副作用的一部分“运行”第一(无功能,只是汇编代码改变了内存并增加堆栈指针)以及第二个运行的副作用部分(在其中执行实际功能)。如果一个功能可以被证明没有副作用,那么它可以被升高到第一部分。我理解正确吗?有道理。另外,你写了'x = f();',但我认为你的意思是'a = f();'(这就是我的代码)。 – corazza
另外,你最后一段的第一句话有点奇怪:*当这种提升发生时,最终的初始值可能会不同,如果它没有发生。* - 你是什么意思?看起来你错过了一个“它”,但总的来说,你所描述的有点混乱,也许发布这个例子会有所帮助? – corazza
@yannbane:这个例子在我引用的部分。我不愿意开始复制它的大部分内容,因为你应该基本阅读它的全部内容。我建议你[转向github](https://github.com/cplusplus/draft),并为自己制作一份标准副本。是的,有两个阶段。第一阶段甚至不会“改变内存” - 初始值只是写入二进制文件并由加载程序加载到内存中。 –