<iostream>与<iostream.h>与"iostream.h"的区别

37

在C++中包含头文件时,用<>括起来时是否包含 .h 的区别是什么?

  1. <>符号括起来时包含 .h 后缀和不包含有何区别?

    #include <iostream> 和 #include <iostream.h>之间的区别是什么?

  2. 用双引号包含头文件名与用<>符号包含头文件名的区别是什么?

    #include <iostream.h> 和 #include "iostream.h" 之间的区别是什么?


1
请参考此问题,了解<>和""之间的区别。 - aib
9个回答

52

简而言之:

iostream.h已经被弃用,这是Stroustrup版本。 iostream 是标准委员会的版本。一般地,编译器将它们都指向相同的东西,但一些旧的编译器可能没有旧版本。在一些奇怪的情况下,它们将同时存在并且不同(以支持遗留代码),那么你必须明确指定。

""<>只是表示在大多数编译器中,在前往库之前检查本地目录中的头文件。


7
作为标准委员会(X3J16)中提出省略.h的人,我最初的意图是解决关于.h、.H、.hpp、.hxx或.h++文件扩展名的争论;或者一些人希望在标准中没有暗示这是磁盘上文件的名称,以便IDE从内部某个位置,如资源文件或编译器的内部,提取预编译头信息。
虽然Unix认为文件名是单个字符串,实际上并没有认可扩展名的概念,但DEC 操作系统有将名称与扩展名分开的传统,并在特定情境下提供“默认扩展名”。这就是我得到的想法,让实现使用任何实现所需的扩展名,并允许实现甚至不将其作为磁盘文件。(当时我是DEC在委员会上的代表。)
区分标准和预标准头文件是一个额外的好处。

1
阅读了几本书后,我推断出 #include<iostream.h> 在我们的程序中包含了一个名为 iostream.h 的特定文件,而 #include<iostream> 仅仅保证了 iostream 库中的所有内容都被包含在我们的程序中。我的理解正确吗? - Shravan

7

这里有一篇不错的文章

简而言之,原因是:

C++标准委员会生产的iostream库版本与CFront实现相差很大。{snip}

为了方便过渡,C++标准委员会宣布,包括标准C++头文件的代码将使用没有扩展名的include指令。这使得编译器供应商可以将旧风格的C++库头文件与.h扩展和新风格的头文件一起发布。

不使用.h版本的优点:

有几个原因说明为什么新代码应该使用无扩展名版本的头文件而不是.h形式。首先是当在现代编译器上编译此类代码时的不可预测性。如前所述,使用.h头文件的结果是特定于实现的。随着时间的推移,给定编译器具有旧样式库的机会减少。


相关:*完全复制的答案,但已经正确归属*。 - Peter Mortensen

2
标准的方法(也是唯一保证可行的方法)是使用<iostream>头文件。在gcc上,<iostream.h>头文件(可能需要被包含为<backward/iostream.h>)将相关声明引入全局命名空间中(因此您不需要std::命名空间前缀)。
"iostream.h"会首先尝试从包含源代码的目录中找到头文件,因为""用于项目中的头文件。<>应始终用于系统头文件,而""应用于自己的头文件。

提及在全局范围内声明“.h”文件并且不需要std命名空间前缀的话,请点赞。 - infinite loop

1
关于标准C++头文件的命名,在X3J16的前两年中,我们就应该在标准C++头文件的扩展名上进行争论。
当时各个供应商使用的扩展名(并受到某些操作系统对文件名的限制的影响),我相信有.h、.H、.h++、.hpp、.HXX等等。在一个库组会议上,我建议我们去掉扩展名,并让实现自己选择默认的文件扩展名(如果include行中没有)或者将名称用作预编译头文件数据库中的键(如果需要)。
(虽然类Unix系统将文件名和“扩展名”视为单个字符串,但我代表DEC在委员会上发言,许多DEC操作系统将扩展名存储在目录中,作为与名称不同的字段。因此,DEC操作系统有一个强烈的传统,根据程序访问文件的目的,应用默认扩展名。告诉汇编程序“X,Y=Z”可能会导致读取输入文件Z.MAC(宏),并写入输出文件X.OBJ和Y.LST。)
无论如何,这避免了一场漫长的无果辩论,所以小组跟随此举,并且Andy Koenig将小组的结论(其中之一)呈现给整个委员会,委员会接受了这个结论。我觉得有点有趣的是,实现者们错过了一个重要的点,他们可以应用自己选择的默认扩展名(我认为这对编辑器和其他工具很有用),但只是忽略了文件名的扩展名。

叹气 抱歉,我现在才意识到我已经写过这个话题了。这种事情发生的时候,我戴错眼镜了。 :-) 希望这个版本能为历史记录增加一些信息。 - Aron Insinga
你可以通过编辑得分最高的回答并删除此回答来将它合并成一个答案。 (但不要包含“Edit:”、“Update:”或类似内容,答案应该看起来像今天写的一样。这是修订历史/编辑摘要的作用。历史信息在修订历史中,不属于当前版本。如果它似乎很明显,我很抱歉,但大多数人做不对。) - Peter Mortensen

1

通常情况下,<> 用于系统或标准库文件,而 "" 用于项目文件。如果编译器在本地找不到文件,则默认使用标准库版本。

至于 .h 文件,在 C 中并不重要。在 C++ 中,我模糊地记得有一个新版本和一个旧版本,没有 .h 应该是新版本,但我甚至不确定旧版本是否仍然存在。


1

对于第一个问题的简单答案是,iostream.h不存在,至少在GCC实现中是这样。如果您使用的是类Unix系统,请键入

% locate iostream.h
/usr/include/c++/3.4.3/backward/iostream.h

% locate iostream
/usr/include/c++/3.4.3/iostream
/usr/include/c++/3.4.3/backward/iostream.h

正如Zee's article所说,iostream.h用于向后兼容。


谢谢,我一直在想实际的文件在哪里。 - Andrew

1

这实际上是两个不同的问题。

  • .h和没有扩展名但同名的头文件之间的区别是历史性的。带有.h扩展名的文件来自最初的C++标准,该标准没有一些现代功能,例如命名空间和模板。对于新标准来说,将相同的功能放入新的头文件中以便使用这些新功能并保留旧的(.h)文件以向后兼容遗留代码更为简单。

  • #include <...>和#include "..."格式之间的区别在于编译器查找文件的顺序。这通常取决于实现,但其思想是<>格式首先查找系统包含目录,而""则在第一个包含它的源文件所在的相同目录中查找。


1
第一点需要进行微小的更正:iostream.h 是预标准版本,在不同编译器之间存在差异。iostream 是在第一个 C++ 标准中添加的。 - KeithB

0
编译器可以自由地添加缺失的“.h”(或任何其他内容)到标准头文件名称中,以确定要读取的实际磁盘文件的名称,如果编译器确实从实际磁盘文件获取标准头文件。因此,用户程序可以说“#include ”,编译器可以聪明地打开一个名为“iostream.h”(或任何其他名称)的文件,在它知道的某个目录中(或通过命令行开关告知)。标准不要求标准头文件在具有任何特定名称的文本实际磁盘文件中。

虽然理论上是允许的,但我不知道有哪个编译器会这样做。 - HolyBlackCat
是的,我认为编译器的作者没有利用头文件名扩展名的能力很遗憾。这样用户、编辑器和其他工具就可以通过名称确定文件所在的语言,同时通过 #include 指令保持可移植性。如果你指的是头文件不来自文本文件,在 VMS 上,编译器可以打开 .TLB(文本库[归档])文件并从中检索头文件:https://forum.vmssoftware.com/viewtopic.php?t=39 - Aron Insinga

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