追求严谨:什么是源文件?什么是头文件?

16

针对此问题,我只关心符合标准的C++,不包括C或C++0x,并且不涉及任何特定于实现的细节。

有时会出现关于#include ""#include <>之间差异的问题。争论通常归结为两个差异:

  1. 具体实现通常在两种形式的不同路径中搜索。这是特定于平台的,不在此问题的范围内。
  2. 标准规定#include <>用于“头文件”,而#include ""用于“源文件”。以下是相关参考:

ISO/IEC 14882:2003(E)

16.2 Source file inclusion [cpp.include]

1 A #include directive shall identify a header or source file that can be processed by the implementation.

2 A preprocessing directive of the form

# include  < h-char-sequence > new-line
searches a sequence of implementation-defined places for a header identified uniquely by the specified sequence between the < and > delimiters, and causes the replacement of that directive by the entire contents of the header. How the places are specified or the header identified is implementation-defined.

3 A preprocessing directive of the form

# include "q-char-sequence" new-line
causes the replacement of that directive by the entire contents of the source file identified by the specified sequence between the " delimiters. The named source file is searched for in an implementation-defined manner. If this search is not supported, or if the search fails, the directive is reprocessed as if it read
# include  < h-char-sequence > new-line
with the identical contained sequence (including > characters, if any) from the original directive.

在上述引文中,我加粗的强调表明这种差异的含义似乎是标准意图区分“头文件”和“源文件”,但是该文件没有定义这些术语或它们之间的差异。几乎没有其他地方提到头文件或源文件。其中一处是:头文件不一定是源文件,头文件名称中由“<”和“>”分隔的序列也不一定是有效的源文件名称(16.2)。这似乎意味着头文件可能不驻留在文件系统中,但它也没有说源文件需要这样做。另一处是:“2词法约定[lex] 1程序的文本以国际标准中称为源文件的单位保存。通过预处理指令#include包括所有标题(17.4.1.2)和源文件(16.2)的源文件,减去任何条件包含(16.1)预处理指令跳过的源代码行,称为翻译单位。[注意:C ++程序不必同时全部翻译。] ”这是我能找到的最接近定义的内容,它似乎意味着头文件不是“程序文本”。但是,如果您使用#include包括头文件,它是否会成为程序文本的一部分?这有点误导人。那么什么是头文件?什么是源文件?

4
一个出人意料的复杂问题。 - dmckee --- ex-moderator kitten
5个回答

8
我的理解是,使用<>尖括号包含的标准头文件不需要实际存在于文件系统中;例如,当实现看到#include <iostream>时,可以自由地启用一组提供功能的“内置”操作。

另一方面,使用#include "xxx.h"引入的“源文件”应该是实际存在于文件系统中的字面文件,并以某种实现相关的方式搜索。

编辑:为了回答你的具体问题,我认为“头文件”仅限于标准规定的可被#include引用的设施:iostreamvector等等,或者作为扩展标准的实现。 “源文件”将是程序员编写或使用的任何非标准设施(如.h文件等)。

3
这似乎是实现定义的,因为明显没有保证 <> 会去寻找一个真正的文件。 - David Thornley
1
@Mike:当然可以……那什么是头文件呢?在大多数系统中,它是某个源文件。但是,标准明确表示它不需要是这样的。也许它是一个文件,但是用非对称密钥加密,以便可以读取但不能更改,并且普通用户无法创建。我认为标准允许这样做。 - David Thornley
1
4.7 头文件 AV 规则 33 #include 指令应使用 <filename.h> 标记法来包含头文件。 注意,相对路径名也可以使用。有关头文件名称的其他信息,请参见 AV 规则 53、AV 规则 53.1 和 AV 规则 55。 原理:通常使用“filename.h”形式来包含本地头文件。但是,由于供应商实现的不幸分歧,只使用 <filename.h> 形式。 - John Dibling
@John:这样解释标准是错误的,因为它并没有这样说。很明显:“指定位置或标识标题的方式是由实现定义的。” - Mike Seymour
一个机器上可以合法地拥有C编译器,该机器除了纸带读取器之外没有其他I/O,并且拒绝所有除了尖括号分隔的标准头文件名之外的include指令,并在内部处理标准化的名称。它不会在某个地方生成可执行文件,而是将编译结果直接存储到RAM中,并在编译完成后立即执行程序。没有任何要求存在创建命名文件的机制,也没有任何要求允许#include使用不可能有效的名称。 - supercat
显示剩余8条评论

4
这是否意味着头文件可以作为源文件来实现,但也可能不是?至于“什么是源文件”,标准没有详细说明似乎很合理,因为“文件”有许多实现方式。

很久以前,我曾经在一个没有文件的Forth系统上工作过,尽管有一个可选的文件系统可用。它使用磁盘块代替文件。假设系统大小足够(它不大),等等,是否可能在其上实现标准的C++95? - David Thornley
@David 是的,我还记得那个很好 - 我在大约1981年写了自己的FORTH系统。我的甚至没有访问CP/M文件系统的能力,它只使用块,但你肯定可以在块之上实现文件,所以我会说“是”。 - anon
非常明智,我期待这就是我的问题的答案。作为一个Windows应用程序背景下的开发者,头文件一直是源文件。了解到C++远不止于在框上运行传统应用程序,我希望能更深入地了解它们之间的差异。 - John Dibling
@DavidThornley: 我不明白为什么不行; 一个具体的实现可以合理地指定`#include“1537 @ 301”将被解释为一项请求,即解释从块301开始的1537个字节数据作为源文本,并插入到当前位置。它也可以合理地指定"fopen"将以相同的方式解释"filenames"。 - supercat

2
标准头文件(string、iostream)不一定是具有这些名称的文件,甚至不一定是文件。只要在你说出它们时,编译器能够找到相应的定义即可。
#include <iostream>

当一定的声明列表进入作用域时,标准得到了满足。具体实现细节是不确定的。(在标准编写时,DOS只能处理8.3文件名,但一些标准头文件名称超过了这个长度)

在我看来,这种情况似乎可以通过“好像”规则来处理。#include <iostream> 显然有明确定义的影响,以及其他可能的影响,“好像”规则本身似乎就可以涵盖它们。 - David Thornley

2
正如您引用的那样:头文件是使用<>包含的内容,源文件是被编译的文件或使用""包含的内容。这些内容来自哪里,以及有哪些非标准头文件可用,取决于实现。标准规定的只是如果包括标准头文件,则定义了什么。
按照惯例,头文件通常是系统范围的东西,而源文件通常是项目(某个定义下的项目)本地的。但是标准明智地没有陷入任何与项目组织有关的细节中;它只给出了非常一般的定义,这些定义与这种约定兼容,将详细信息留给实现和/或用户。
几乎所有的标准都处理经过预处理的程序,在此时不存在源文件或头文件,只有最后一个引用定义的翻译单元。

0

嗯……

我粗略的了解是,<> 和 "" 之间的区别是从 C 语言中继承而来的(虽然这并未被规范定义),<> 搜索系统和编译器提供的头文件,而 "" 则搜索本地和用户指定的路径。

上面的定义在某种意义上似乎与该用法一致,但限制了“头文件”的使用范围,即由编译器或系统提供的内容,排除用户提供的代码,即使它们具有传统的“接口放在头文件中”的形式。

无论如何,非常有趣。


标准并不限制“header”的使用 - 它由实现决定。如果实现者决定它可以是用户代码,那么它就可以是用户代码。 - Mike Seymour

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接