【问题标题】:twisted logic: a global variable in one file refers to an extern variable but is also referred by that extern variable扭曲的逻辑:一个文件中的全局变量引用外部变量,但也被该外部变量引用
【发布时间】:2015-08-28 11:35:43
【问题描述】:

文件A.cpp:

#include <iostream>
extern int iA;
extern int iB= iA;
int main()
{
std::cout<<iA<<','<<iB;
}

文件B.cpp

extern int iB;
extern int iA = 2*iB;

编译链接运行,在调试和发布模式下出来是0,0 我的问题是它是如何工作的,为什么在链接阶段没有问题? 我正在使用 VC++2003。

【问题讨论】:

  • gcc 报告:fileb.cpp:2: warning: 'iA' initialized and declared 'extern' extern int iA = 2*iB; ^
  • @PiotrNycz VisualStudio 中没有警告。 gcc 给出的内容看起来根本不像警告。我敢打赌,如果我有,它会给出同样的警告:extern int iA = 10;
  • 是的,你会有同样的警告,顺便说一句 - gcc 也会产生0,0

标签: c++ compilation linker external


【解决方案1】:

初始化程序会覆盖 extern 关键字,因此这并没有什么“神奇”之处:您只是在不同的翻译单元中声明和定义了两个完全不相关的变量。

来自Standard for Programming Language C++ - Chapter 3.1

声明是一个定义,除非它声明一个函数而不指定函数的主体 (8.4),它包含extern 说明符 (7.1.1) 或 linkage-specification25 (7.5) 既不是初始化器也不是 函数体,它在类定义(9.2,9.4)中声明一个静态数据成员,它是一个类名声明(9.1),它是一个不透明枚举声明(7.2),它是一个模板参数 (14.1),它是一个函数声明器中的一个参数声明 (8.3.5),它不是一个函数定义,或者它是 typedef 声明 (7.1.3)、alias-declaration (7.1.3)、using-declaration (7.3.3 )、static_assert-declaration(第 7 条)、属性声明(第 7 条)、空声明(第 7 条)、或使用指令 (7.3.4)。

因此,您的程序等同于以下内容:

fileA.cpp

#include <iostream>
extern int iA;
int iB= iA;
int main()
{
std::cout<<iA<<','<<iB;
}

fileB.cpp

extern int iB;
int iA = 2*iB;

在其他任何事情发生之前,这两个对象都必须经过静态初始化(按位全零)。稍后发生动态初始化时,取决于 fileA.cpp 或 fileB.cpp 中的静态存储持续时间对象是先初始化(您不知道会是什么顺序)要么iB被初始化为零iA(然后iA被初始化为2*iB,正如预期的那样),或者iA被初始化为零iB乘以2,仍然是零(然后@ 987654333@ 被初始化为零 iA)。

无论哪种方式,通过定义明确的语义,这两个对象最终都将具有零值。

【讨论】:

  • 我相信这不是未定义的行为,而是未指定的行为。如3.6.2 Initialization of non-local variables [basic.start.init] 所述 - 初始化有两个阶段 - 静态和动态。在这种情况下,静态初始化会导致变量归零。然后动态初始化不会改变这个状态。未指定来自不同源单元的动态初始化顺序 - 但两种可能的顺序给出相同的结果。
  • 在边界上偷偷修复
  • 零初始化(这是静态初始化中常量初始化的替代方法)将变量设置为零值,这可能所有位都为零,但不一定。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-12-28
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多