我不明白以下代码示例的作用以及它是如何做到的:
#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()
,但这意味着初始化的顺序是相反的(我也可能错误的是初始化是什么,或当它发生时)。
答案 0 :(得分:34)
这个问题有点微妙;有关详细信息,请参阅C ++ 11 3.6.2。
对我们来说重要的是,“静态存储持续时间的非局部变量”(或通俗话说的“全局变量”)有两个初始化阶段:静态初始化阶段和动态初始化阶段。静态阶段首先出现。它看起来像这样:
int a = 0;
int x = 22;
之后运行动态初始化:
a = f();
关键是静态初始化根本不“运行” - 它只包含在编译时已知的设置值,因此在任何执行发生之前已经设置了这些值。初始化int x = 22;
静态的原因是初始化器是一个常量表达式。
有些情况下,动态初始化可能被提升到静态阶段(但不必),但这不是其中一种情况,因为它不符合
初始化的动态版本在初始化之前不会更改名称空间作用域的任何其他对象的值
当这种提升发生时,允许的结果初始值可能与未发生时的初始值不同。标准中有一个这样的“不确定”初始化的例子。
答案 1 :(得分: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的答案解释了为什么会这样。