为什么引用某些导出的 const 变量的某些 const 变量的值为 0?
-
06-09-2019 - |
题
考虑以下。我有两个导出常量,如下所示:
// 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)。
解决方案
由于cMyConstDouble被声明为extern,编译器不能呈现其值,并且不产生对cMyConstDouble2编译时间初始化。由于cMyConstDouble2未编译时初始化,它的相对的初始化以便cAnotherDouble2是随机的(未定义)。请参见静态初始化惨败更多信息。
其他提示
我不打算动用我的脚趾成的extern这里的问题,但为什么你根本不要将consts在相应的头文件,而忘记了“出口”他们使用的extern?这是consts应该如何在C ++中使用的,为什么它们具有内部链接。
在换句话说:
// someheader.h
const double cMyConstDouble = 3.14;
const double cMyConstDouble2 = 2.5*cMyConstDouble;
和#包括该文件,无论你需要他们。
这是很危险的事情在一个源文件中的一个静态变量取决于在另一个CPP文件中的另一静态变量。检查静态初始化惨败了解更多信息。
如果你改变初始化 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
如果动态初始化没有改变任何其他静态存储变量(满足 你的 代码),并且当静态初始化产生的值与动态初始化产生的值相同时,当所有不需要静态初始化的对象将被动态初始化时(也满足 你的 code) - 然后允许静态初始化变量。上面的代码中两个变量也满足这两个条件 d2
和 d1
:
分析 d2
= d1
不更改任何其他静态存储变量- 当两个
d2
和d1
动态初始化,然后d2
将被初始化为0.0
, , 因为d2
之前已定义d1
, ,以及动态初始化d2
会抢到的价值d1
从静态初始化之后的状态开始(其中只有零初始化d1
发生)。
分析 d1
= fd()
不更改任何其他静态存储变量- 当两个
d2
和d1
动态初始化,然后= fd()
将初始化d1
到1.0
.
所以,编译器可能会初始化 d1
静态地 1.0
, ,因为可选静态初始化的两个条件都满足。
如果 编译器决定初始化
d1
和d2
动态地,那么d2
将被初始化为0.0
, ,因为它将获取的值d1
因为它是在零初始化之后。然而, 如果 编译器决定初始化
d1
静态地和d2
动态地,那么d2
将被初始化为1.0
, ,由于动态初始化d2
将获取完全初始化的值d1
因为它是在静态初始化之后。
我不确定有什么价值 d2
那时候 d1
和 d2
不过,是静态初始化的。也就是说,是否 d2
应该抓住 0.0
或者 1.0
, ,因为没有为静态初始化定义顺序。
(1) 当考虑具有静态存储持续时间的对象的初始化顺序时,常量表达式也包括算术常量表达式(不仅仅是整型常量表达式)。