来自“C ++ Primer,5th Edition”,第407页:
所有静态持续时间变量共享以下两个初始化 特性:
未初始化的静态变量的所有位都设置为0.
静态变量只能用常量表达式初始化。
常量表达式可以使用文字常量,const和enum 常量和sizeof运算符。以下代码片段 说明了这些要点:
int x; // x set to 0 int y = 49; // 49 is a constant expression int z = 2 * sizeof(int) + 1; // also a constant expression int m = 2 * z; // invalid, z not a constant int main() {...}
我的问题是 - 为什么这是标准?这是什么(实际)原因。
否则我们会受到什么伤害?
特别是,我发现很难找到无效的理由:
int m = 2 * z; // invalid, z not a constant
因为z
本身在编译时已经知道。
答案:
简单地说,根据标准,不能保证在main
的第一个陈述之前的指令将按顺序完成。
虽然所有静态存储都将在任何其他初始化之前进行零初始化,但可以保证。
这意味着在我给出的示例中:int m = 2 * z;
是一个未定义的行为,m可以评估为2*0=0
,也可以评估为2 *(2 * sizeof(int)+ 1)。 / p>
超出“C ++标准 - ANSI ISO IEC 14882 2003”3.6.2(第44页):
具有静态存储持续时间(3.7.1)的对象应进行零初始化 (8.5)在进行任何其他初始化之前。
...
允许实现执行a的初始化 命名空间范围的对象,静态存储持续时间为静态 初始化即使不需要进行这样的初始化也是如此 静态...
...
重要的一点:
因此,如果对象obj1的初始化引用了 具有静态存储持续时间的命名空间范围的对象obj2 可能需要动态初始化并在以后定义 相同的翻译单元,未指定是否为obj2的值 used将是完全初始化的obj2的值(因为obj2是 静态初始化)或仅仅是obj2的值 零initialized.`
进一步阅读有关此类问题:
http://www.parashift.com/c++-faq-lite/ctors.html#faq-10.14
编辑:回答。 Pubby是正确的答案(并被接受)但我真的错过了“因此......”部分。另外,我认为我添加的链接可能很有用。
答案 0 :(得分:4)
z
已初始化为2 * sizeof(int) + 1
,但稍后可将其更改为其他值。通过明确要求将const表达式作为初始化程序,很明显您将获得什么值。如果允许非常量表达式,则最终可能会根据初始化顺序使用不同的值。根据const的要求,你很清楚你得到了什么。
答案 1 :(得分:3)
静态初始化(技术上持续初始化)需要常量表达式,但静态存储持续时间变量不需要。
int x; // 0 initialized
int y = 49; // statically initialized
int z = 2 * sizeof(int) + 1; // statically initialized
int m = 2 * z; // dynamically or statically initialized
3.6.2归零,零初始化和常量初始化称为静态初始化;所有其他初始化是 动态初始化。在进行任何动态初始化之前,应执行静态初始化。
动态初始化可以依赖于在编译时无法确定的函数和其他东西。如果编译器可以确定结果,则允许编译器执行静态初始化。
您发布的示例将起作用,但它可能会导致更复杂的初始化问题,因为某些变量可以动态或静态初始化:
inline double fd() { return 1.0; }
extern double d1;
double d2 = d1; // unspecified:
// may be statically initialized to 0.0 or
// dynamically initialized to 1.0
double d1 = fd(); // may be initialized statically to 1.0
答案 2 :(得分:1)
引用的文字完全错了,而且一直都是。静态变量 可以使用您想要的任何表达式进行初始化(前提是 表达式本身是合法的,并且不使用其他变量 尚未初始化)。比如:
int i = f();
非常频繁,即使在命名空间范围内,当然也是静态的 具有类类型和用户定义构造函数的变量甚至更多 频繁。
答案 3 :(得分:0)
我能想到的唯一原因是static
变量存储在可执行文件的.rdata
段中,因为它是只读部分可执行文件,把那些更改的东西放在那里,没有任何意义。
答案 4 :(得分:0)
我认为你的例子是有效的。从14882年:2011年,
可以在翻译过程中评估常量表达式。
和
变量 在单个翻译单元中定义的有序初始化应按其顺序初始化 翻译单位中的定义。
在您的示例中,z和m位于相同的翻译单元中。所以我认为m是由一个常量表达式初始化的。