C++全局变量初始化顺序

C++ global variable initialization order

本文关键字:顺序 初始化 全局变量 C++      更新时间:2023-10-16

我不明白下面的代码示例做了什么以及它是如何做到的:

#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("%dn", x);
}

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

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

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

显然情况并非如此。但是什么呢?这个代码实际上是做什么的

在评估a = f()之前,似乎x被设置为22,但这意味着初始化的顺序颠倒了(我也可能对什么是初始化或何时初始化有误)。

这个问题有点微妙;有关详细信息,请参阅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 = 22;替换b = g();会导致打印1 23。Kerrek SB的回答解释了为什么会这样。