编译器如何知道其他.cpp文件如何使用静态常量成员? 有人可以向我解释这个来自最权威的ISO C++ FAQ的例子吗?代码如下所示: // Fred.h class Fred { public: static const int maximum = 42; // ... }; // Fred.cpp #include "Fred.h" const int Fred::maximum; // ...

编译器如何知道其他.cpp文件如何使用静态常量成员? 有人可以向我解释这个来自最权威的ISO C++ FAQ的例子吗?代码如下所示: // Fred.h class Fred { public: static const int maximum = 42; // ... }; // Fred.cpp #include "Fred.h" const int Fred::maximum; // ...,c++,static,initialization,constants,datamember,C++,Static,Initialization,Constants,Datamember,我无法得到的声明是: 如果您使用Fred::max的地址,例如通过引用传递它或显式地说&Fred::max,编译器将确保它具有唯一的地址。否则,Fred::maximum甚至不会占用进程静态数据区域的空间 编译器单独处理.cpp文件,不知道其他文件如何处理当前正在处理的文件中定义的数据。那个么,编译器如何决定是否应该分配一个唯一的地址呢 原始项在这里:编译器不做任何决定。对于未定义静态类成员的翻译单元,编译器生成的对象模块包含对符号的未解析引用 当所有目标模块链接在一起时,链接器负责完成作业,并

我无法得到的声明是:

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

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


原始项在这里:

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


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

常见问题解答条目说明
const int Fred::max必须在一个编译单元中定义。但是,只有当变量由程序调用时(例如,如果引用绑定到它),这才是正确的

如果未使用odr变量,则可以省略定义

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

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


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

这意味着编译器/链接器可以执行整个程序分析,并在确定未使用该定义后,自行作出优化决定以省略该定义

即使行
const int Fred::max
定义为为为
int
分配内存,这是允许的优化,因为一致性程序无法测量是否实际为未使用odr的
int
分配了内存

该FAQ条目的作者显然希望编译器/链接器能够做到这一点


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

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

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

>该FAQ条目的作者显然希望编译器/链接器会这样做。在这个FAQ条目中,让我困惑的部分是,它将任务归因于编译器,而这肯定是链接器的工作-编译器对此类任务一无所知东西。我的理解正确吗,常见问题解答的措辞只是有点草率?(另外,5分钟评论编辑窗口grrrr。)@sigil使用“编译器”一词涵盖源代码和可执行文件之间的所有内容并不少见