【问题标题】:How does compiler know how other .cpp files use a static const member?编译器如何知道其他 .cpp 文件如何使用静态 const 成员?
【发布时间】:2016-09-30 01:38:24
【问题描述】:

有人可以从最权威的 ISO C++ 常见问题解答中解释一下这个例子吗?代码如下:

// Fred.h
class Fred {
public:
  static const int maximum = 42;
  // ...
};

// Fred.cpp
#include "Fred.h"
const int Fred::maximum;
// ...

而我无法得到的陈述是:

如果您曾经获取 Fred::maximum 的地址,例如通过引用传递它或明确地说 &Fred::maximum,编译器将确保它具有唯一的地址。否则,Fred::maximum 甚至不会占用您进程的静态数据区中的空间。

编译器单独处理 .cpp 文件,不知道其他文件如何处理当前正在处理的文件中定义的数据。那么,编译器如何决定它是否应该分配一个唯一的地址呢?

原文在这里:https://isocpp.org/wiki/faq/ctors#static-const-with-initializers

【问题讨论】:

    标签: c++ static initialization constants datamember


    【解决方案1】:

    编译器不决定任何事情。对于未定义static 类成员的翻译单元,编译器生成的对象模块包含对该符号的未解析引用。

    当所有对象模块链接在一起时,链接器负责完成工作,并将所有未解析的引用从引用静态符号的翻译单元解析到已定义符号的单独翻译单元。

    【讨论】:

      【解决方案2】:

      FAQ 条目说const int Fred::maximum; 必须在一个编译单元中定义。但是,只有当变量被程序设置为 odr-used 时(例如,如果引用绑定到它),这才是正确的。

      如果变量不是odr-used,那么可以省略定义。

      但是,如果变量实际上是 odr-used 但没有定义,那么它是未定义的行为,不需要诊断。通常,如果需要变量的地址但省略了定义,则优质链接器会省略“未定义引用”错误。

      但您并不总是希望依赖未定义行为的特定表现形式。因此,最好始终包含定义 const int Fred::maximum;


      您问题中引用的段落旨在解决潜在的程序员问题:“好吧,我不能通过在某些情况下省略定义来在我的静态数据区域中保存 4 个字节吗?”

      这是说编译器/链接器可以执行整个程序分析,并在确定未使用定义后做出自己的优化决定以省略定义。

      即使const int Fred::maximum; 行被定义为为int 分配内存,这是允许的优化,因为符合标准的程序无法测量内存是否实际分配给int这不是odr-used

      该 FAQ 条目的作者显然希望编译器/链接器实际上会这样做。


      标准中关于odr-use的措辞旨在支持以下编译/链接模型:

      • 如果某些代码要求变量具有地址,则目标文件将包含对该变量的引用。
      • 优化可能会移除一些从未调用过的代码路径等。
      • 在链接时,当解析这些引用时,该引用将绑定到变量的定义。

      它不需要编译器产生“未定义的引用”错误消息,因为这会使编译器更难优化。另一个优化阶段可能会完全删除包含引用的目标文件部分。例如,如果发现 odr-use 只发生在从未调用过的函数中。

      【讨论】:

      • > 该 FAQ 条目的作者显然希望编译器/链接器实际上会这样做。
      • 在这个FAQ项目中让我感到困惑的部分是它将任务归于编译器,而这绝对是链接器的工作——编译器对这些事情一无所知。我是否正确理解常见问题解答的措辞在这里有点草率? (另外,5 分钟评论编辑窗口 grrrr。)
      • @sigil 使用“编译器”这个词来涵盖源代码和可执行文件之间的所有内容并不少见
      猜你喜欢
      • 1970-01-01
      • 2016-10-01
      • 1970-01-01
      • 2011-07-19
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-08-03
      • 2023-03-26
      相关资源
      最近更新 更多