我目前的理解是这样的。如果我错了,请纠正我。当我将C ++库(例如开源项目)包含到我的项目中时,我必须包含.h文件,以便编译器了解所包含库的接口。然后,包含的库的已编译代码将由链接器链接。
但是现在在编译期间,包含的头文件需要另一个依赖项。如果我要包含此依赖项的头文件,在包含每个依赖项之前,这不会变成某种递归循环吗?为什么需要它?这不应该是链接程序的关注点吗?编译的库包含依赖项。
我偶然发现了使用Xcode 9.4的这个项目。
答案 0 :(得分:1)
编译器将代码翻译成机器语言。然后使用链接器将所述代码与其他机器代码串在一起。谷歌更多关于我写的东西,如果感到困惑;这是一种简化,缺少更详细的信息。
例如,当您键入#include <cstdint>
时,另一个单独的程序 preprocessor 会在#include <cstdint>
上进行模式替换(如果您愿意),并将该行替换为cstdint.hh
文件的全部内容。替代发生在机器代码的翻译过程甚至开始之前。
通常,这些#include <...>
文件是经过精心编写的,因此您无需追逐 other #include
。但是,这不是保证。
答案 1 :(得分:0)
您确定的风险存在。它不是自动的。如果a.h
包含包含b.h
的{{1}},则嵌套包含将没有问题。
如果c.h
同时包含a.h
和b.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都由编译器单独处理,而正是这个编译器超越了双重定义。链接器不太关心重复。对于链接器来说,重复的函数定义是一个问题,而类定义则不是。