【问题标题】:Why do includes need further dependencies?为什么包含需要进一步的依赖?
【发布时间】:2018-08-13 12:23:36
【问题描述】:

我目前的理解是这样的。如果我错了,请纠正我。当我在我的项目中包含一个 C++ 库(例如开源项目)时,我必须包含 .h 文件,以便编译器知道所包含库的接口。所包含库的编译代码然后由链接器链接。

但现在在编译过程中,包含的头文件需要另一个依赖项。如果我包含此依赖项的头文件,在包含每个依赖项之前,这不会变成一些递归循环吗?为什么需要它?这不应该是链接器的关注点吗?编译后的库包含依赖项。

我使用 Xcode 9.4 偶然发现了这个项目。

【问题讨论】:

  • 这样想可能会有所帮助:每个#include 语句都相当于将整个包含的代码复制粘贴到#include 的位置。所以对于链接器来说,一个包含另一个的 .h 文件相当于只有一个包含两者定义的头文件。
  • #include 部分与链接器阶段 BTW 无关。

标签: c++ xcode compilation


【解决方案1】:

编译器将代码翻译成机器语言。然后使用链接器将所述代码与其他机器代码串在一起。如果感到困惑,请在 Google 上更多地了解我写的内容;这是一个缺少细节的简化。

例如,当您键入 #include <cstdint> 时,另一个单独的程序 预处理器 会在 #include <cstdint> 上进行模式替换(如果您愿意),并将该行替换为cstdint.hh 文件。替换发生在机器代码的翻译过程甚至开始之前。

通常,这些#include <...> 文件是仔细编写的,因此您无需追逐其他 #include。但是,这不是保证。

【讨论】:

  • 所以我遇到的问题是我include的库写的不仔细,因为头文件使用了对另一个库的include?​​span>
  • 其实正好相反;该库缺少我可以推测的#include 文件。即它试图在其他一些 .hh 中使用代码,但它本身不包含它,然后向你抱怨它!
【解决方案2】:

您识别的风险存在。不过,这不是自动的。如果a.h 包含b.h 包含c.h,则嵌套包含没有问题。

如果a.h 包含b.hc.h,并且b.h 也间接包含c.h,您可能会遇到问题。这里的风险不是太多的递归,而是c.h的内容的双重定义。

通常的解决方案是每个标题都以

开头
#ifndef A_H_INCLUDED
#define A_H_INCLUDED

// actual contents of "a.h"

结尾
#endif // A_H_INCLUDED

现在,c.h 的第二个包含是无害的。发生这种情况时,C_H_INCLUDED 将已由第一个包含定义,因此第二个包含被完全跳过。一些编译器足够聪明,可以识别这种模式,甚至不会第二次读取c.h,从而节省了几毫秒的磁盘 I/O。

链接器无法解决这个问题,因为双定义问题发生在链接器参与之前。它发生在单个翻译单元的级别。在包含所有 .h 文件之后,翻译单元基本上是一个 .cpp 文件。每个 TU 都由编译器单独处理,正是这个编译器遍历了双重定义。链接器不太关心重复。重复的函数定义是链接器的问题,类定义不是。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2016-05-18
    • 2023-03-18
    • 1970-01-01
    • 2021-11-27
    • 2016-09-13
    • 2020-12-08
    • 1970-01-01
    相关资源
    最近更新 更多