多次#included 受保护的 header 文件如何位于不同的翻译单元中?

How a multiple times #included guarded header file will be inside different translation units?

我知道#inclusion 通常被描述为文本 copy-pasting 预处理器指令。现在,如果 header 是#include guarded 或#pragma onced,那么我们如何描述第一个翻译单元之后实际发生的事情,#include 说 header?

没有“第一”翻译单位。所有翻译单元在概念上都是并行翻译的(当然,在实践中你可能最终一次编译一个,但这没关系)。

每个翻译单元都以空白开始。从技术上讲,这并不完全正确,因为您可以在命令行添加 #defines,并且还有一些预定义的宏,但无论如何,没有翻译单元会有 #defines 的“记忆”在任何其他翻译单元中执行。因此,尽管有守卫,一个 header 可能会 #included 多次。只是不会#included多次变成一个翻译单元.

这意味着您仍然必须注意避免多重定义:例如,如果您的 header 包含一个全局变量,那么您必须确保它是 const(因此它将具有内部 linkage) 或显式声明它 inline(将所有定义合并为一个)或 extern(抑制 header 中的定义,以便您可以将定义放入单个翻译中单位)。

尽管 include guards 不会阻止跨多个翻译单元的多个定义,但它们确实会阻止单个翻译单元内的多个定义,这很重要,因为即使某些实体可能在程序中被定义多次, 仍然不允许多个定义出现在同一个翻译单元中。例如,如果您在 header 中有一个 inline 全局变量,那么多个翻译单元可以包含该 header 并且定义将全部折叠到 [=36= 处的单个定义中] 时间,但如果任何 one 翻译单元多次定义该变量,您将收到编译错误。因此,这样的header必须有一个include guard。