为什么编译器不能避免自己两次导入头文件?


13

C ++的新手!因此,我正在阅读以下内容:http : //www.learncpp.com/cpp-tutorial/110-a-first-look-at-the-preprocessor/

护头板

因为头文件可以包含其他头文件,所以有可能最终导致头文件被多次包含的情况。

因此,我们制定了预处理程序指令来避免这种情况。但是我不确定-为什么编译器不能 ... 不能两次导入相同的东西?

鉴于标头保护符是可选的(但显然是一种很好的做法),几乎让我认为在某些情况下您确实想导入两次。尽管我根本无法想到任何这种情况。有任何想法吗?


在MS编译器上,有#pragma once一个告诉编译器仅包含该文件一次。
CodesInChaos

Answers:


27

如新语言所示,它们可以。

但是所有这些年前(当时C编译器是多个独立的阶段)就做出了设计决定,现在为了保持兼容性,预处理器必须以某种方式采取行动,以确保旧代码能够按预期进行编译。

由于C ++继承了从C处理头文件的方式,因此保持了相同的技术。我们支持旧的设计决策。但是更改其工作方式的风险太大,有可能破坏代码。因此,现在我们必须教该语言的新用户如何使用包含警戒。

如果您故意多次将头文件包括在内,则头文件有两个技巧(实际上确实提供了有用的功能)。尽管如果我们从头开始重新设计范例,我们可以使它成为包含文件的非默认方式。


7

否则,它就不会那么具有表现力,因为他们选择保持与C的兼容性,从而继续使用预处理程序而不是传统的打包系统。

我想到的一件事是,我有一个项目是一个API。我有两个头文件x86lib.hx86lib_internal.h。由于internal很大,因此我将“ public”位隔离到x86lib.h中,因此用户不必为编译留出更多时间。

尽管这引入了一个有趣的依赖问题,所以我最终在x86lib_internal中遇到了这样的流程

  1. 设置内部预处理程序定义
  2. 包括x86lib.h(在定义内部时,以某种方式执行该操作很聪明)
  3. 做一些事情并介绍x86lib.h中使用的一些东西
  4. 设置AFTER预处理器定义
  5. 再次包含x86lib.h(这一次它将忽略所有内容,除了依赖于x86lib_internal元素的单独AFTER部分之外

我不会说这是最好的方法,但是它实现了我想要的。


0

自动重复标头排除的一个困难是C标准在包含文件名的含义方面相对沉默。例如,假设正在编译的主文件包含#include "f1.h"#include "f2.h",为这些伪指令找到的文件都包含#include "f3.h"。如果f1.hf2.h处于不同目录中,但是通过搜索包含路径找到了,则不清楚#include那些文件中的指令旨在加载同一f3.h文件还是不同文件。

如果增加包含相对路径的包含文件的可能性,情况将变得更加糟糕。在某些情况下,头文件对嵌套include指令使用相对路径,并且希望避免对提供的头文件进行任何更改,在某些情况下,可能需要在项目目录结构中的多个位置重复头文件。即使存在该头文件的多个物理副本,也应在语义上将它们视为单个文件。

如果该#pragma once指令允许标识符遵循once,并且如果标识符与先前遇到的#pragma once指令中的标识符匹配,则编译器应跳过该文件的语义,那么语义将是明确的;否则,语义将是明确的。一种可以告诉您#include指令将加载与#pragma once早期指令相同的带有标签的文件的编译器,通过跳过该文件而不再次打开它可以节省一些时间,但是这种检测在语义上并不重要,因为将跳过该文件是否文件名是否被识别为匹配项。但是,我不知道有任何编译器以这种方式工作。有一个编译器观察文件是否与模式匹配#ifndef someIdentifier / #define someIdentifier / #endif [for that ifndef] / nothing following和处理这样的事情是等同于上面#pragma once someIdentifier,如果someIdentifier 保持定义,本质上是一样的。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.