2

考虑以下。我有两个导出的常量,如下所示:

// somefile.h
extern const double cMyConstDouble;
extern const double cMyConstDouble2;

// somefile.cpp
const double cMyConstDouble = 3.14;
const double cMyConstDouble2 = 2.5*cMyConstDouble;

这些常量现在在其他地方引用以定义两个静态(本地可见)常量:

// someotherfile.cpp
#include "somefile.h"
static const double cAnotherDouble = 1.1*cMyConstDouble;
static const double cAnotherDouble2 = 1.1*cMyConstDouble2;
printf("cAnotherDouble = %g, cAnotherDouble2 = %g\n",
       cAnotherDouble, cAnotherDouble2);

产生以下输出:

cAnotherDouble = 3.454, cAnotherDouble2 = 0

为什么第二个双0?我正在使用 .NET 2003 C++ 编译器(13.10.3077)。

4

4 回答 4

9

我不打算在这里深入探讨 extern 的问题,但是为什么您不将 const 放在适当的头文件中而忘记使用 extern“导出”它们呢?这就是 const 应该在 C++ 中使用的方式,以及它们具有内部链接的原因。

换句话说:

// someheader.h
const double cMyConstDouble = 3.14;
const double cMyConstDouble2 = 2.5*cMyConstDouble;

和#include 该文件,无论您需要它们。

于 2009-05-28T12:42:05.570 回答
8

因为 cMyConstDouble 被声明为 extern,所以编译器不能采用它的值并且不会为 cMyConstDouble2 生成编译时初始化。由于 cMyConstDouble2 未在编译时初始化,因此其相对于 cAnotherDouble2 的初始化顺序是随机的(未定义)。有关更多信息,请参阅静态初始化惨败

于 2009-05-28T12:42:51.730 回答
3

这是危险的事情,因为一个源文件中的一个静态变量依赖于另一个 cpp 文件中的另一个静态变量。查看静态初始化惨败以获取更多信息。

于 2009-05-28T12:44:08.950 回答
2

如果您在cMyConstDouble2此处将初始化更改为:

const double cMyConstDouble2 = 2.5*3.14;

那么你的程序应该表现正确。原因是这些变量

  • 有POD类型
  • 用常量表达式初始化(1)

在静态初始化时初始化。这些初始化包括

  • 对所有具有静态存储持续时间的对象进行零初始化
  • 使用常量表达式初始化的 POD 的初始化

在您显示的变量中,仅cMyConstDouble满足在静态初始化时完全初始化的两个条件。但是,cMyConstDouble2没有,因为它的初始化器不满足常量表达式的要求。特别是,它包括一个不具有整数类型的变量(这里,它具有浮点类型)。但是,算术常量表达式允许使用浮点文字。 这就是为什么是算术常数表达式。这就是为什么将初始化程序更改为需要静态初始化的原因。2.5*3.14


cMyConstDouble2如果你继续使用非常数表达式会发生什么?答案是,你不知道。该标准允许对该变量进行静态初始化,但不要求它这样做。在您的情况下,它是动态初始化的 - 因此它在静态初始化时间之后的值仍然为零。为了感受这有多复杂,这里有一个例子:

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

如果动态初始化不更改任何其他静态存储变量(在您的代码中满足),并且当静态初始化将产生与动态初始化产生的值相同的值时,当所有不需要静态初始化的对象都将被动态初始化时(在您的代码中也很满意) - 然后允许静态初始化变量。这两个条件在上面的代码中对于变量d2和也都满足d1

分析d2

  • = d1不更改任何其他静态存储变量
  • d2d1都被动态初始化时,d2则将被初始化为0.0,因为d2在 之前定义d1,并且动态初始化d2d1在静态初始化之后获取状态的 as 值(仅d1发生零初始化)。

分析d1

  • = fd()不更改任何其他静态存储变量
  • d2d1都被动态初始化时,= fd()则将初始化d11.0

因此,编译器可能会d1静态初始化为1.0,因为可选静态初始化的两个条件都满足。

  • 如果编译器决定动态初始化,d1则将初始化为,因为它将在零初始化之后获取 的值。d2d20.0d1

  • 但是如果编译器决定d1静态和d2动态初始化,d2则将被初始化为1.0,因为 的动态初始化d2将在静态初始化之后获取完全初始化的值d1

不过,我不确定什么d2时候d1 d2静态初始化的值是什么。也就是说,是否d2应该抓取0.01.0,因为没有为静态初始化定义顺序。


(1)在考虑具有静态存储持续时间的对象的初始化顺序时,常量表达式也包括算术常量表达式(不仅是整型常量表达式)。

于 2009-05-28T16:00:20.037 回答