【问题标题】:Why initialization of a static variable is restricted to constant expressions?为什么静态变量的初始化仅限于常量表达式?
【发布时间】:2011-12-06 13:38:00
【问题描述】:

来自“C++ Primer,第 5 版”,第 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)。

超出“C++ 标准 - ANSI ISO IEC 14882 2003”3.6.2(第 44 页):

具有静态存储持续时间(3.7.1)的对象应为零初始化 (8.5) 在任何其他初始化发生之前。

...

一个实现被允许执行一个初始化 具有静态存储持续时间的命名空间范围的对象作为静态 初始化,即使不需要进行此类初始化 静态...

...

还有最重要的一点:

因此,如果对象 obj1 的初始化引用了 具有静态存储持续时间的命名空间范围的对象 obj2 可能需要动态初始化并在后面定义 相同的翻译单元,未指定obj2的值是否 used 将是完全初始化的 obj2 的值(因为 obj2 是 静态初始化)或将只是 obj2 的值 零初始化。`

进一步阅读此类问题:

http://www.parashift.com/c++-faq-lite/ctors.html#faq-10.14

编辑:输入答案。 Pubby's 是正确的答案(并被接受),但我真的错过了“结果......”部分。另外,我认为我添加的链接可能有用。

【问题讨论】:

  • 你用的是什么编译器?像这样的例子对我来说编译得很好。
  • 您可能会混淆“静态变量”和“静态初始化”的不同概念。静态变量可以静态或动态初始化。

标签: c++ static


【解决方案1】:

静态初始化(技术上是常量初始化)需要常量表达式,但静态存储持续时间变量不需要。

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】:

    z 被初始化为2 * sizeof(int) + 1,但稍后可以更改为另一个值。通过明确要求将 const 表达式作为初始化程序,很清楚您将获得什么值。如果您允许非常量表达式,您最终可能会根据初始化顺序得到不同的值。有了 const 要求,你得到什么就很清楚了。

    【讨论】:

    • 如果z 被声明为const,你认为它会改变吗?
    • 如果我的想法是正确的,它应该改变,但是当你问我是否正确时,我会怀疑。
    【解决方案3】:

    引用的文字完全是错误的,而且一直都是。静态变量 可以使用您想要的任何表达式进行初始化(前提是 表达式本身是合法的,并且不使用其他变量 尚未初始化)。比如:

    int i = f();
    

    非常频繁,即使在命名空间范围内,当然也是静态的 具有类类型和用户定义构造函数的变量甚至更多 经常。

    【讨论】:

      【解决方案4】:

      我能想到的唯一原因是 static 变量存储在可执行文件的 .rdata 段中,并且由于它是可执行文件的 readonly 部分,放在那里会改变的东西,没有任何意义。

      不过,我可能错了。

      【讨论】:

      • 静态变量是可以改变的,就是初始化需要一个const表达式。
      【解决方案5】:

      我认为你的例子是有效的。从 14882:2011 开始,

      常量表达式可以在翻译过程中求值。

      变量 在单个翻译单元中定义的有序初始化应按照它们的顺序进行初始化 翻译单元中的定义。

      在您的示例中,z 和 m 在同一个翻译单元中。所以我认为 m 是由一个常量表达式初始化的。

      【讨论】:

        猜你喜欢
        • 2023-03-22
        • 1970-01-01
        • 2012-02-01
        • 1970-01-01
        • 1970-01-01
        • 2012-08-18
        • 2018-06-01
        • 2011-08-22
        • 2010-12-22
        相关资源
        最近更新 更多