头文件在整个程序中只包含一次?

新手上路,请多包涵

我知道这是一个常见问题,但我仍然无法完全理解它。

在从多个不同的源文件和头文件生成的 C 或 C++ 程序中,当使用头保护时,每个头文件是否只包含在整个代码中一次?

之前有人告诉我,一个头文件(带有包含保护)只会在一个翻译单元中包含一次,但在整个代码中会包含多次。这是真的?

如果它在整个代码中只包含一次,当一个文件希望包含它并且预处理器检测到它已经被包含时,希望使用它的那个文件如何知道它在以前包含的代码中的下落?

原文由 Engineer999 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 801
1 个回答

这是过程:

 source           header   source header header
   \           /        \   |      /   /
    \         /          \  |     /   /
  PREPROCESSOR            PREPROCESSOR
       |                      |
       V                      V
 preprocessed code      preprocessed code
       |                      |
    COMPILER               COMPILER
       |                      |
       V                      V
  object code              object code
             \            /
              \          /
               \        /
                 LINKER
                   |
                   V
               executable

预处理

#include 是第一步。它指示预处理器处理指定的文件,并将结果插入到输出中。

If A includes B and C , and B includes C , the preprocessor’s output for A 将包含 C 的处理文本两次。

这是一个问题,因为它会导致重复声明。一种补救方法是使用预处理器变量跟踪是否包含源代码(也称为标头保护)。

 #ifndef EXAMPLE_H
#define EXAMPLE_H

// header contents

#endif

第一次, EXAMPLE_H 未定义,预处理器将评估 ifndef / endif 块中的内容。第二次,它将跳过该块。所以处理后的输出 改变 了,定义只包含一次。

这很常见,以至于一些编译器实现了一个非标准指令,该指令更短并且不需要选择唯一的预处理器变量:

 #pragma once

// header contents

您可以确定您希望 C/C++ 代码的可移植性,以及使用哪个标头保护。

头文件保护将确保每个头文件的内容在翻译单元的预处理代码中最多出现一次。

编译

编译器从您预处理的 C/C++ 生成机器代码。

通常,头文件仅包含声明,而不包含实际定义(也称为实现)。编译器包含一个符号表,用于当前缺少定义的任何内容。

链接

链接器组合目标文件。它将定义(又名实现)与对符号表的引用进行匹配。

可能是两个目标文件提供了定义,而链接器将采用一个。如果您将可执行代码放在标头中,就会发生这种情况。这在 C 中通常不会发生,但在 C++ 中却经常发生,因为模板。

标头“代码”,无论是声明还是定义,都包含在所有目标文件中多次,但链接器将所有这些合并在一起,因此它仅在可执行文件中出现一次。 (我不包括多次出现的内联函数。)

原文由 Paul Draper 发布,翻译遵循 CC BY-SA 4.0 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题