为什么包含需要进一步的依赖关系?

时间:2018-08-13 12:23:37

标签: c++ xcode compilation

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

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

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

2 个答案:

答案 0 :(得分:1)

编译器将代码翻译成机器语言。然后使用链接器将所述代码与其他机器代码串在一起。谷歌更多关于我写的东西,如果感到困惑;这是一种简化,缺少更详细的信息。

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

通常,这些#include <...>文件是经过精心编写的,因此您无需追逐 other #include。但是,这不是保证。

答案 1 :(得分:0)

您确定的风险存在。它不是自动的。如果a.h包含包含b.h的{​​{1}},则嵌套包含将没有问题。

如果c.h同时包含a.hb.h,并且c.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,从而节省了几毫秒的磁盘I / O。

链接器无法解决此问题,因为双重定义问题是在涉及链接器之前发生的。它发生在各个翻译单位的级别。在包含所有.h文件之后,翻译单元基本上是一个.cpp文件。每个TU都由编译器单独处理,而正是这个编译器超越了双重定义。链接器不太关心重复。对于链接器来说,重复的函数定义是一个问题,而类定义则不是。