#include <>和#include ""的含义

15

4
你的意思是,“不会给出完全相同的输出”是什么意思? - Johannes Schaub - litb
2
不应该有这个 - 你能提供更多细节和示例输出吗? - Vinay Sajip
1
使用 "stdio.h" 或 <stdio.h> 对于 gcc 输出没有任何区别。 - LB40
3
#pragma once 和#ifndef MY_HEADER_FILE_H #define MY_HEADER_FILE_H 有什么区别? - dmckee --- ex-moderator kitten
1
@dmckee:这不是重复的问题。你链接的答案(错误地)说明了区别在于搜索的执行方式。这个新问题是关于是否有除了搜索之外的其他不同之处的(即它基于其他问题)。 - Dan Moulding
好的... 我所说的不同输出是指 VC++ 在 #include "" 时给了我一个(相关的)警告,并且它无法检测到 #include <> 的问题。 - fulmicoton
8个回答

24

最根本的区别在于搜索的路径不同。

对于“系统”包含文件,应使用尖括号形式,对于项目本地包含文件,则应使用普通引号。


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

23
C语言标准规定<>用于“头文件”,而""用于“源文件”。不过,“源文件”并不像你想象的那样。标准中所说的“源文件”包括我们俗称的“头文件”(以及我们通常称之为“源文件”的东西)。
当标准谈到“头文件”时,并没有特别地指出是指文件。标准并不要求头文件存在于文件中。它们可以内置在编译器中,标准并不关心。
所以,<>""真正的区别在于,<>用于头文件""用于源文件。如果你知道要包含的源代码是一个文件,那么应该使用""
实际上,编译器针对<>""使用不同的搜索算法。这是允许的,因为标准规定任何一种都是实现定义的。但这并不是标准所表达的真正区别。

我曾经有过将一个.c文件直接包含到源代码中的经历。这并不是一种好的做法,我不建议这样做,但确实是可行的。无论你#include什么,只要最终生成的C源代码是有效的就可以了。;-) - DevSolar
@DevSolar:确实如此。但在我来自的地方,#include一个.c文件被认为是纯粹的邪恶。 :) - Dan Moulding
这里也是一样。但我感觉很好。;-)(实际上,这是你所谓的Unix C语言“高速课程”,在这个课程中,讲师和我们两个学生在五天内翻阅了460页的书。有一天我需要反复使用相同的函数,但休息时间从未足够长,无法将其转化为应该有的两个C文件加一个H文件再加Makefile的正确设置,因此我只需包含另一个C文件即可。当讲师看到我在做什么时,他相当...激动。;-) - DevSolar
相关:在g++visual c++中的实现。 - Alexander Malakhov

7
丹·莫尔丁说得对;unwind,hacker和Nick Bastin都错了。抱歉。
#include <...>

这里讲的是头文件,它们不一定是文件系统中的文件,也可以是编译器内部的文件。

#include "..."

#include指令用于包含文件,仅当找不到这样的文件时,才会默认回退到#include <...>

这些头文件和文件在哪里以及如何查找,以及是否应该使用<>来表示系统文件,使用""来表示项目文件,这确实是一个常见的约定,完全取决于编译器和项目。

C标准(ISO/IEC 9899:1999)如下所述(重点在于我):

6.10.2 源文件包含

限制

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

语义

形如

#include <h-char-sequence> new-line

的预处理指令搜索一系列由实现定义的地方,以特定序列唯一标识的标题为界定符,替换该指令的整个内容。如何指定这些地方或标识头文件是实现定义的。

形如

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

的预处理指令将该指令的内容替换为由指定序列标识的源文件的整个内容,该序列在引号之间。命名的源文件按照实现定义的方式进行搜索。如果不支持此搜索,或者搜索失败,则将指令重新处理,就好像它读取了

#include <h-char-sequence> new-line

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


如果你能指出标准中“源文件”被定义为与“头文件”不同的地方,那么你可以继续保持高傲态度。实际上唯一提到甚至试图定义“源文件”的地方是在一个脚注中,它说(在5.1.1.2(5)):“源文件,...不一定要存储为文件,也不需要这些实体与任何外部表示之间存在一对一的对应关系。” - Nick Bastin
此外,在C99标准的理由中,“未在标准中包含显式规则的主要原因是描述可移植文件系统结构的不可行性。”(6.10.2-5)“头文件”和“源文件”的唯一区别在于标准保留了一些头文件名 - “标准指定了一组包含文件名,这些文件名必须映射到不同的主机文件名。如果没有这样的要求,使用包含的文件编写可移植程序将是不可能的。”(6.10.2-15) - Nick Bastin
我不想“高高在上”。我一直认为标准将头文件和源文件视为两个不一定相同的东西,并从这个立场进行了辩论。在文档中搜索,我发现5.1.1.1(1),6.4.7(2),6.10.2,脚注156)到7.1.2,以及7.1.2(3)支持头文件和源文件是两个不同的事物的概念。 - DevSolar

6

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

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


在引号和尖括号的使用上存在差异,这是因为编译器设计者认为应该如此,而不是受到标准的规定。 - Nick Bastin
@Nick:标准确实说它们应该不同,但并没有明确指出搜索算法应该不同。 - Dan Moulding
尼克,几乎所有的编译器设计师都会关注这个问题。这很重要,不是吗?;-) - Michael Krelin - hacker

3
对于gcc编译器来说,使用<>和""头文件有所不同。如果从作为预处理器提供的-isystem目录中包含<>头文件,则不会为所包含的头文件发出警告。在某些情况下,使用-Werror会产生巨大的影响。
英特尔编译器也有-isystem指令,因此可能适用于icc。
更不用说查找目录的差异了,这太明显了,不值一提。

1

#include <somefile.h>

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

#include "somefile.h"

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


0

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

如果编译器实现了预编译头文件,则可能会将其用于一种包含形式,但不用于另一种。如果预编译头文件与实际头文件不同步,那么根据所包含的内容不同,您将得到不同的结果。


-1

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

根据ISO C99标准的第6.10.2节,<>和""的搜索路径都是实现定义。 标准视角下它们之间唯一的区别是,如果无法解析,使用""将回退到<>。(不要被标准似乎在“头文件”和“源文件”之间进行区分所绊倒 - 实际上除了某些名称被保留 - “stdio.h”等之外,标准并没有定义区别。)


如果您仔细阅读标准,就会发现<>适用于头文件,而""适用于源文件。请注意,标准中使用的“源文件”与口语交流中通常所指的含义不同。 - Dan Moulding
重要的区别在于,头文件不需要驻留在文件系统中... - DevSolar
标准可能会这样说,但并不总是如此。 - Chris Huang-Leaver
@DevSolar:从标准的相关部分(5.1.1.2(5))中可以看出,“源文件...不一定需要存储为文件,也不需要这些实体与任何外部表示之间存在一对一的对应关系。” - Nick Bastin
7.1.2(1)的注脚159:“头文件不一定是源文件,头文件名称中的<和>分隔序列也不一定是有效的源文件名称。”你还坚持认为标准没有定义差异吗? - Dan Moulding
显示剩余3条评论

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