【问题标题】:#include <> and #include "" [duplicate]#include <> 和 #include "" [重复]
【发布时间】:2010-11-24 22:28:39
【问题描述】:

可能重复:
what is the difference between #include <filename> and #include “filename”

除了编译器将搜索的路径之外,这两种#include 语法之间是否存在根本区别?

我感觉 Intel 的编译器并没有给出完全相同的输出。

【问题讨论】:

  • 你的意思是“没有给出完全相同的输出”?
  • 不应该有 - 你能提供更多细节和示例输出吗?
  • gcc 的输出与 "stdio.h" 或 完全没有区别。
  • @dmckee:这不是重复的。您链接到(错误地)的答案表明不同之处在于搜索的执行方式。这个新问题是关于除了搜索之外是否还有其他不同的搜索(即它建立在另一个问题的基础上)。

标签: c++ compiler-construction include


【解决方案1】:

根本区别搜索路径。

您应该对“系统”包含使用尖括号形式,对项目本地包含使用常规引号。

【讨论】:

  • 实际上这可能是真的,但根据 C 语言标准,真正的区别在于编译器应该搜索 header 还是 file我>。 (提示:标题不一定是文件,尽管它们几乎总是)。
  • 有趣...关于“标题不必是文件”。原谅我的无知,他们还能是什么?
  • @Rich:例如,它们可能是编译器/预处理器内置的。预处理器无需在文件系统上搜索文件,而是可以在包含标准头文件时将硬编码的代码插入到自身中。或者它可以查询数据库以获取标题的内容,从互联网下载标题......你明白了。但是如果你不要求,而是要求“stddef.h”,那么编译器应该首先搜索一个名为stddef.h的文件,即使它有stddef.h内置(或通过其他方式提供)。
  • 考虑预处理的头文件,预处理器/编译器根本不需要通过头文件源...
【解决方案2】:

C 语言标准规定&lt;&gt; 用于“标题”,"" 用于“源文件”。现在,不要对“源文件”这件事大发雷霆。当标准说“源文件”时,它并不意味着你的想法。标准中使用的术语“源文件”包括我们通俗地称为“头文件”(除了我们通常所说的“源文件”)。

当标准谈论“标题”时,它根本不是专门谈论文件。该标准不要求标头作为文件存在。它们可以内置到编译器中,用于所有标准的关心。

所以&lt;&gt;""之间的真正区别在于&lt;&gt;用于headers""用于文件。如果您知道要包含的源是一个文件,那么您应该使用""

实际上,编译器对&lt;&gt;"" 使用不同的搜索算法。这是标准允许的,因为用于任一搜索算法的搜索算法是实现定义的。但这并不是标准所表达的真正区别。

【讨论】:

  • 我有时会破解一个源以实际包含一个 .c 文件。这不是很好,我不会推荐它,但它确实是可能的。 什么你#include并不重要,只要结果是有效的C源代码。 ;-)
  • @DevSolar:确实如此。但是我来自#include 一个.c 文件的地方被认为是纯粹的邪恶。 :)
  • 这里也是。但我觉得很喜欢。 ;-) (实际上,这就是你所说的 Unix 的 C 语言“高速课程”,讲师和我们两个学生在五天内读完了 460 页的书。我一遍又一遍地需要相同的功能一天,但是休息时间还不够长,无法将其变成应有的正确的两个 C 和一个 H 加 Makefile 设置,所以我只是简单地包含了另一个 C 文件。教练很……当他看到我在做什么时很激动。;-)
  • 相关:在g++visual c++中实现
【解决方案3】:

Dan Molding 做对了;放松,黑客,尼克巴斯汀弄错了。对不起。

#include <...>

用于headers,它甚至不需要是文件系统中的文件,但可以例如在编译器内部。

#include "..."

用于文件,只有在找不到此类文件时,才会默认返回#include &lt;...&gt;

这些头文件和文件的查找方式和位置,系统文件是否应该使用,项目文件是否应该使用“”,这确实是一个常见的约定,完全取决于编译器和项目.

C 标准 (ISO/IEC 9899:1999) 说(强调我的):

6.10.2 源文件包含

约束

#include 指令 应标识头文件或源文件 可以处理的 实施。

语义

表单的预处理指令

#include &lt;h-char-sequence&gt; new-line

搜索一个序列 a 的实现定义的位置 唯一标识的标头 之间的指定序列 分隔符,并导致替换 该指令由整个 标头的内容。地方如何 已指定或标头已标识 是实现定义的。

表单的预处理指令

#include "q-char-sequence" new-line

导致替换那个 指令的全部内容 由 之间的指定序列 分隔符。命名的源文件是 以 > 实现定义的方式搜索。 如果这 不支持搜索,或者如果 搜索失败,指令是 重新处理,好像它已阅读

#include &lt;h-char-sequence&gt; new-line

具有相同的 包含的序列(包括 > 字符,如果有的话)从原始 指令。

【讨论】:

  • 如果你能指出标准中“源文件”被定义为与“头文件”不同的地方,那么你就可以继续前进了。唯一真正提到甚至试图定义“源文件”的地方是在一个脚注中(在 5.1.1.2 (5) 中):“源文件,......不一定要存储为文件,也不需要有任何这些实体与任何外部表示之间一一对应。”
  • 进一步,在 C99 标准的基本原理中 - “显式规则未包含在标准中的主要原因是描述可移植文件系统结构的不可行性。” (6.10.2-5) “头文件”和“源文件”之间的唯一区别是标准保留了一些头文件名 - “标准指定了一组包含文件名,这些文件名必须映射到不同的主机文件名。如果没有这样的要求,就不可能使用包含文件编写可移植程序。” (6.10.2-15)
  • 我不想“骑高马”。我一直认为标准认为头文件和源文件是两个不一定相同的东西,并从那个位置争论。搜索文档,我发现 5.1.1.1 (1)、6.4.7 (2)、6.10.2、脚注 156) 到 7.1.2 和 7.1.2 (3) 支持头文件和源文件的概念两种不同的东西。
【解决方案4】:

引号 指示首先在当前目录中搜索,然后在系统目录中搜索(在编译器/预处理器中硬编码或使用-I 指定的路径)。通过使用尖括号,您首先选择不搜索当前目录。

编译器输出绝对不依赖于引号,因为它是在预处理阶段处理的。除了由于搜索行为改变而包含不同文件的情况。

【讨论】:

  • 就引号和尖括号的不同而言,它们这样做是因为编译器设计者认为他们应该这样做,而不是因为标准的任何规定。
  • @Nick:标准确实说它们应该不同,但没有说搜索算法应该不同。
  • Nick,或多或少的所有编译器设计师。这很重要,不是吗? ;-)
【解决方案5】:

对于 gcc 编译器, 和 "" 标头之间存在 区别。如果从作为 -isystem 提供给预处理器的目录中包含 标头,则不会针对包含的标头发出警告。使用 -Werror,这在某些情况下会产生巨大的影响。

英特尔编译器也有 -isystem 指令,因此它可能也适用于 icc。

更不用说查找目录的差异太明显了。

【讨论】:

    【解决方案6】:

    #include &lt;somefile.h&gt;

    将检查系统包含路径(包括为项目添加的任何其他路径)。

    #include "somefile.h"

    将检查应用程序工作文件夹。 (即与其中包含#include 语句的源文件相同的文件夹)。

    【讨论】:

      【解决方案7】:

      警告:这纯属猜测。我对英特尔编译器没有足够的经验来知道它是否以这种方式工作,我也不知道有任何编译器可以这样做。

      如果编译器实现了预编译的头文件,它可能会将它们用于一种形式的包含而不是另一种。如果预编译的标头与实际标头不同步,您会得到不同的结果,具体取决于包含的内容。

      【讨论】:

        【解决方案8】:

        一般来说没有技术差异,任何人告诉你的一切都只是本地风格,可能受到过去编译器的影响 - 许多现代编译器以完全相同的方式实现初始搜索(通常其他常见行为可通过命令行获得选项)。该标准将行为留给了实现者,没有特别的理由来支持这两种语法。

        根据 ISO C99 标准的第 6.10.2 节, 和“”的搜索路径都是实现定义的。在标准看来,它们之间的唯一区别是如果无法解决,使用 "" 将退回到 。 (不要被似乎区分“头文件”和“源文件”的标准所迷惑——除了保留某些名称这一事实之外,标准实际上没有定义任何区别——“stdio.h "等)

        【讨论】:

        • 如果您仔细阅读该标准,您会发现 适用于 headers 而 "" 适用于 源文件。请注意,标准中使用的“源文件”并不意味着它通常在口语对话中的含义。
        • @Dan Moulding:如果标准对源文件和标头进行了实质性区分,这实际上很重要,但实际上并没有。
        • 最大的区别是头文件不需要驻留在文件系统中......
        • 标准可能会这么说,但并非总是如此。
        • @DevSolar:“源文件”也不需要驻留在文件系统中——标准从未使用过这样的词或对其进行定义。事实上,这些东西是实现定义的真正原因是标准不假定“文件”如何存储在您的操作系统中(否则像 VMS 这样的操作系统中面向记录的文件系统将无法支持 C 编译器)
        猜你喜欢
        • 2013-03-17
        • 1970-01-01
        • 2016-07-06
        • 2013-06-03
        • 1970-01-01
        • 1970-01-01
        • 2015-10-08
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多