注:以下例子仅是讨论C++语法,绝非推荐在实践中利用它们。
例1
例2
例3
令人惊讶的是(起码我第一次看到惊讶了一番),以上都是合法的c++,决没有涉及任何未定义行为。 关键在于,C++对全局变量(实际上对于静态生存期的变量都是如此)的初始化分了2个阶段:
阶段1:静态初始化
如果一个全局变量用一个常量表达式来初始化,例如例2的y=3,这就是静态初始化。如果一个全局变量没有用常量表达式来初始化,那么会首先将其初始化为0。
阶段2:动态初始化
例如上面的x = y就是动态初始化了。
也就是说,c++程序在启动时,首先会进行静态初始化,然后再进行动态初始化。
对于例2,y=3会在静态初始化阶段执行,而x = y在后面执行,所以最后y值为3,x值也为3。
所以对于例1来说,x和y首先初始化为0,然后互相赋值,因此最后它们的值都是0。
对于例3,情况有点复杂,因为还有一条c++规则:编译器可以选择将一个本应该动态初始化的变量静态初始化,条件是它的动态初始化版本没有改变任何其它先前声明的名字空间域的变量,并且动态初始化版本的结果和静态初始化版本的结果相同。那么对于例3,y=f(),即可以当作动态初始化,也可以在静态初始化。这样,虽然y最后的值都是3,但x的结果就可能是0或者是3,要看编译器的实现了。不过我觉得这种情况比较少,因为编译器还要额外分析一些东西,何必这样折磨自己呢?
貌似很少有教科书会说这些东西,讲C++的书一般对于全局变量的使用,都是建议不要写出相互依赖的代码来。
但从语法上来说,C在这方面的规定比C++要简单很多,C压根就不允许在定义全局变量时象上面的例子那样写出x=y来,即使y是const也不行。
参考:
ISO C++ 2003, 3.6.2
例1
extern
int
y;
int x = y;
int y = x;
int main() {}
int x = y;
int y = x;
int main() {}
例2
extern
int
y;
int x = y;
int y = 3 ;
int main() {}
int x = y;
int y = 3 ;
int main() {}
例3
inf f()
{
return 3;
}
int x = y;
in y = f();
{
return 3;
}
int x = y;
in y = f();
令人惊讶的是(起码我第一次看到惊讶了一番),以上都是合法的c++,决没有涉及任何未定义行为。 关键在于,C++对全局变量(实际上对于静态生存期的变量都是如此)的初始化分了2个阶段:
阶段1:静态初始化
如果一个全局变量用一个常量表达式来初始化,例如例2的y=3,这就是静态初始化。如果一个全局变量没有用常量表达式来初始化,那么会首先将其初始化为0。
阶段2:动态初始化
例如上面的x = y就是动态初始化了。
也就是说,c++程序在启动时,首先会进行静态初始化,然后再进行动态初始化。
对于例2,y=3会在静态初始化阶段执行,而x = y在后面执行,所以最后y值为3,x值也为3。
所以对于例1来说,x和y首先初始化为0,然后互相赋值,因此最后它们的值都是0。
对于例3,情况有点复杂,因为还有一条c++规则:编译器可以选择将一个本应该动态初始化的变量静态初始化,条件是它的动态初始化版本没有改变任何其它先前声明的名字空间域的变量,并且动态初始化版本的结果和静态初始化版本的结果相同。那么对于例3,y=f(),即可以当作动态初始化,也可以在静态初始化。这样,虽然y最后的值都是3,但x的结果就可能是0或者是3,要看编译器的实现了。不过我觉得这种情况比较少,因为编译器还要额外分析一些东西,何必这样折磨自己呢?
貌似很少有教科书会说这些东西,讲C++的书一般对于全局变量的使用,都是建议不要写出相互依赖的代码来。
但从语法上来说,C在这方面的规定比C++要简单很多,C压根就不允许在定义全局变量时象上面的例子那样写出x=y来,即使y是const也不行。
参考:
ISO C++ 2003, 3.6.2