#include <filename>和#include"filename"有什么区别?

quest49 1980 c c++ include header-files c-preprocessor

在C和C++编程语言中,使用尖括号和在include语句中使用引号有什么区别,如下所示?

  1. #include <filename>
  2. #include "filename"

quest49.. 1152

实际上,差异在于预处理器搜索包含文件的位置.

对于#include <filename>预处理器以依赖于实现的方式搜索,通常在编译器/ IDE预先指定的搜索目录中.此方法通常用于包括标准库头文件.

对于#include "filename"预处理器首先在与包含该指令的文件相同的目录中进行搜索,然后按照用于#include <filename>表单的搜索路径进行搜索.此方法通常用于包括程序员定义的头文件.

有关搜索路径的GCC 文档中提供了更完整的描述.

  • 声明:"预处理器在同一目录中搜索..."在实践中可能是正确的,但标准规定命名的源文件是"以实现定义的方式搜索".请参阅piCookie的回答. (109认同)
  • 虽然你的答案似乎是"真实的",因为这是按惯例工作的实现数量,你应该仔细看看aib和piCookie的答案.他们都指出(由C标准的措辞支持)真正的区别是包含"标题"而不是包含"源文件"(不,这并不意味着".h"与".". C").在此上下文中的"源文件"可以(通常是,并且几乎总是应该是)".h"文件.标头不一定需要是文件(编译器可以例如包括静态编码的标头,而不是文件中的标头). (44认同)
  • 那些不喜欢答案的人,请举一个实际的例子,说错了. (6认同)
  • "...预处理器在与要编译的文件正在编译的文件相同的目录中进行搜索." 这句话并不完全正确.我对这个问题感兴趣,因为我很好奇实际答案是什么,但我知道这不是真的,因为至少使用gcc时,你指定一个额外的包含路径-I,它将搜索用#include"filename指定的文件. H" (3认同)

piCookie.. 627

唯一的方法是阅读您的实现文档.

C标准中,第6.10.2节第2至4段规定:

  • 表单的预处理指令

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

    搜索的用于实现定义的地方的序列报头由之间的指定序列唯一地识别<>分隔符,并且使得由所述的全部内容替换该指令的标头.如何指定场所或标识的头是实现定义的.

  • 表单的预处理指令

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

    导致由分隔符之间的指定序列标识的源文件的全部内容替换该指令".以实现定义的方式搜索指定的源文件.如果不支持此搜索,或者搜索失败,则会重新处理该指令,就像它读取一样

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

    使用>原始指令中相同的包含序列(包括字符,如果有的话).

  • 表单的预处理指令

    #include pp-tokens new-line
    

    (允许与前两种形式中的一种不匹配).include指令中的预处理标记处理与正常文本一样.(当前定义为宏名称的每个标识符将替换为其预处理标记的替换列表.)所有替换后生成的指令应与前两个表单中的一个匹配.将a <>预处理令牌对或一对"字符之间的一系列预处理标记组合成单个标题名称预处理标记的方法是实现定义的.

定义:

  • h-char:源字符集的任何成员,除了换行符和 >

  • q-char:源字符集的任何成员,除了换行符和 "

  • "这是C标准如何冗长而不回答你的问题" (93认同)
  • 相关:在[g ++](http://gcc.gnu.org/onlinedocs/cpp/Include-Syntax.html)和[visual c ++]中实现(http://msdn.microsoft.com/en-us/library /36k2cdd4(v=vs.110).aspx) (91认同)
  • @piCookie <filename>和"filename"搜索实现定义的位置.那么区别是什么呢 ? (20认同)
  • @Stefan,我只是引用了一个没有说明INCLUDE_PATH的标准.您的实施可能会这样做,而我的可能不会.最初的问题通常是C,而不是gcc(我认为不使用INCLUDE_PATH)或Microsoft C(我认为可以)或任何其他问题,所以它不能一般地回答,而是必须引用每个实现的文档. (10认同)
  • 与所有这些情况一样,具体示例(尤其是常见情景)非常有用并且同样受到重视.不必要的钝性通用答案没有那么多的实际用途. (9认同)
  • "<filename>和"filename"都搜索实现定义的地方".这个答案几乎有用吗? (7认同)
  • 我不知道这是怎么在C中,如果我读上面的标准引号,```和`>`之间的序列不一定是文件名.任何唯一定义标题的东西都可以.在C++中,这意味着<algorithm>不一定映射到名为"algorithm"或"algorithm.h"的文件.如何实际命名此文件,或者文件系统中的文件是否是文件是实现定义的.但是第二个版本中的q-char序列确实包含一个真实的文件名. (6认同)
  • @entropy:在这样的论坛中,你无法回答你的问题.对于一个特定的编译器来说,一个答案是正确的可能对另 每个特定的实现/编译器都应该有义务说明差异,这是唯一可靠的知道方式.其他几个答案给出了示例,也许您的实现在其中一个中提到. (5认同)
  • @ DaveVoyles-MSFT这是唯一正确的答案,因为问题没有指定哪个实现,只是"C和C++编程语言".一些实现如何处理#include已经在评论中指出,这是他们所属的地方,因为他们不会真正回答这个问题. (5认同)
  • @ onmyway133标准允许_two_ _alternative_搜索机制.如果未实现_an_ _alternative_搜索机制(对于_include_""),_include_""将作为_include_ <>.然而,标准中的引用肯定应该有一个总结 - 没有人不得不浪费时间搞清楚它意味着什么. (4认同)
  • "了解的唯一方法是阅读您的实施文档." 或者在Stack Overflow上询问某人.我很欣赏你参加"教学时刻",但我担心这种态度很快就会过时. (4认同)
  • 人们来到这里以他们能够理解的方式向他们解释事物.简单地指向神秘的文档是没有用的.那些糟糕的文档正是为什么我们这么多人都在这个问题上. (3认同)
  • 引用标准的目的是为了表明该标准没有提供答案,因为这两种形式之间的差异(如果有的话)完全取决于实施,这就是为什么引用标准是建议您阅读实施的相关文件,因为OP没有说明他们的实施是什么.说穿了:没有标准答案,所以你必须查阅你的实施相关文件,以了解你的具体情况. (3认同)
  • @MaximEgorushkin看到Alexander Malakhov对描述gcc和visual C++实现的链接的评论.任何其他商业编译器都应该有类似的文档.IMO,亚历山大的评论应该是答案的一部分. (2认同)

aib.. 244

<和>之间的字符序列唯一地引用标题,该标题不一定是文件.实现几乎可以随意使用字符序列.(但是,大多数情况下,只需将其视为文件名并在包含路径中进行搜索,就像其他帖子所述.)

如果使用该#include "file"表单,则实现首先查找给定名称的文件(如果支持).如果不是(支持),或者搜索失败,则实现的行为就像使用了other(#include <file>)形式一样.

此外,存在第三种形式,当#include指令与上述任何一种形式都不匹配时使用.在这种形式中,一些基本的预处理(例如宏扩展)在#include指令的"操作数"上完成,并且结果预期与其他两种形式中的一种匹配.

  • +1,这可能是这里最简洁和正确的答案.根据标准(piCookie在他的回答中引用),唯一的*真正*区别是"标题"与"源文件".搜索机制是以任一方式实现定义的.使用双引号意味着你打算包括"源文件",而尖括号意味着你打算包括"头",正如你说的,可能不是一个文件都没有. (42认同)
  • @MaximEgorushkin:VAX/VMS C编译器将所有C运行时库头保存在单个文本库文件中(类似于unix存档),并使用`<`和`>`之间的字符串作为索引到图书馆. (13认同)
  • 十年来,我一直在阅读"标准标题不一定是文件形式".关心提供一个真实世界的例子? (9认同)
  • @Maxim Yegorushkin:我也想不出任何现有的现实世界的例子; 但是,除非标题不必是文件,否则MS-DOS不能存在完整的C11编译器.这是因为某些C11标头名称与"8.3"MS-DOS文件名限制不兼容. (9认同)
  • 请参阅Dan Molding对quest49的回答的评论; 标准标题不必是文件形式,它们可以是内置的. (2认同)

Yann Droneau.. 99

这里的一些好的答案引用了C标准,但忘记了POSIX标准,特别是c99(例如C编译器)命令的特定行为.

根据The Open Group Base Specifications Issue 7,

-I 目录

在查找常用位置之前,更改搜索名称不是绝对路径名的标头的算法,以查找目录路径名所指定的目录.因此,名称以双引号("")括起来的标题应首先在#include行的文件目录中搜索,然后在-I选项中命名的目录中搜索,最后在通常的位置搜索.对于名称用尖括号("<>")括起来的标题,只能在-I选项中指定的目录中搜索标题,然后在通常的位置搜索标题.在-I选项中命名的目录应按指定的顺序进行搜索.实现应在单个c99命令调用中支持至少十个此选项的实例.

因此,在符合POSIX标准的环境中,使用符合POSIX标准的C编译器,#include "file.h"可能会首先搜索./file.h,其中.是带有#include语句的文件所在的目录,同时#include <file.h>,可能/usr/include/file.h首先搜索,/usr/include系统定义在哪里通常的标题位置(似乎没有POSIX定义).

  • @osgx:在[`c99`](http://pubs.opengroup.org/onlinepubs/9699919799/utilities/c99.html)的POSIX规范中找到了这个措辞(或类似的东西) - 这是POSIX名称对于C编译器.(POSIX 2008标准很难提及C11; 2013年对POSIX 2008的更新没有改变它所提到的C标准.) (5认同)

Suraj Jain.. 40

海湾合作委员会的文件说明了以下两者之间的区别:

使用预处理指令包含用户和系统头文件‘#include’.它有两个变种:

#include <file>

此变体用于系统头文件.它在标准的系统目录列表中搜索名为file的文件.您可以使用-I选项将目录添加到此列表中(请参阅调用).

#include "file"

此变体用于您自己的程序的头文件.它首先在包含当前文件的目录中搜索名为file的文件,然后在quote目录中搜索,然后使用相同的目录<file>.您可以使用该-iquote选项将目录添加到报价目录列表中.‘#include’无论是用引号还是尖括号分隔的参数,都表现为字符串常量,因为无法识别注释,并且不会扩展宏名称.因此,#include <x/*y>指定包含名为的系统头文件x/*y.

但是,如果文件中出现反斜杠,则它们被视为普通文本字符,而不是转义字符.没有处理适合C中字符串常量的字符转义序列.因此,#include "x\n\\y"指定包含三个反斜杠的文件名.(有些系统将'\'解释为路径名分隔符.所有这些也都以‘/’相同的方式解释.它最易于使用‘/’.)

如果文件名后面的行上有任何内容(注释除外),则会出错.


Stefan Steig.. 39

它确实:

"mypath/myfile" is short for ./mypath/myfile

.是其中所述文件的任一目录#include被包含在,和/或编译器的当前工作目录,和/或default_include_paths

<mypath/myfile> is short for <defaultincludepaths>/mypath/myfile

如果./<default_include_paths>,那么它没有什么区别.

如果mypath/myfile在另一个包含目录中,则行为未定义.

  • 不,`#include"mypath/myfile"`不等于`#include"./mypath/myfile"`.正如piCookie的回答所说,双引号告诉编译器以实现定义的方式进行搜索 - 包括在为#include <...>`指定的位置进行搜索.(实际上,它可能是等价的,但只是因为,例如,`/ usr/include/mypath/myfile`可以称为`/ usr/include /./ mypath/myfile` - 至少在Unix上是这样的系统). (8认同)

Arkadiy.. 29

<file>包括告诉预处理到搜索-I目录和在预定义的目录第一,然后在.c文件的目录.在"file"包括告诉预处理器搜索源文件的目录第一,然后恢复到-I和预定义.无论如何都会搜索所有目的地,只有搜索顺序不同.

2011标准主要讨论"16.2源文件包含"中的包含文件.

2表单的预处理指令

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

搜索一系列实现定义的位置,以查找由<和>分隔符之间的指定序列唯一标识的标头,并使标头的整个内容替换该指令.如何指定场所或标识的头是实现定义的.

3表单的预处理指令

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

导致由"delimiters"之间的指定序列标识的源文件的全部内容替换该指令.以实现定义的方式搜索指定的源文件.如果不支持此搜索,或者搜索失败,该指令被重新处理,就像它读取一样

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

使用原始指令中相同的包含序列(包括>字符,如果有的话).

请注意,如果找不到文件,"xxx"表单会降级<xxx>.其余的是实现定义的.

  • 您是否可以提供C标准中指定此`-I`业务的参考? (2认同)

skyking.. 18

按标准 - 是的,它们是不同的:

  • 表单的预处理指令

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

    搜索一系列实现定义的位置,以查找由<>分隔符之间的指定序列唯一标识的标头,并使标头的整个内容替换该指令.如何指定场所或标识的头是实现定义的.

  • 表单的预处理指令

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

    导致由"分隔符之间的指定序列标识的源文件的全部内容替换该指令.以实现定义的方式搜索指定的源文件.如果不支持此搜索,或者搜索失败,则会重新处理该指令,就像它读取一样

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

    使用>原始指令中相同的包含序列(包括字符,如果有的话).

  • 表单的预处理指令

    #include pp-tokens new-line
    

    (允许与前两种形式中的一种不匹配).include指令中的预处理标记处理与正常文本一样.(当前定义为宏名称的每个标识符将替换为其预处理标记的替换列表.)所有替换后生成的指令应与前两个表单中的一个匹配.将a <>预处理令牌对或一对"字符之间的一系列预处理标记组合成单个标题名称预处理标记的方法是实现定义的.

定义:

  • h-char:源字符集的任何成员,除了换行符和 >

  • q-char:源字符集的任何成员,除了换行符和 "

请注意,该标准没有说明实现定义方式之间的任何关系.第一种形式以一种实现定义的方式搜索,另一种以(可能是其他)实现定义的方式搜索.该标准还规定了某些包含文件应存在(例如<stdio.h>).

在形式上你必须阅读编译器的手册,但是通常(按照传统),#include "..."表单会搜索#include首先找到的文件的目录,然后#include <...>搜索表单搜索的目录(包含路径,例如系统头文件) ).

  • @KyleStrand那是因为同一文本是标准中相关部分的引用 - 文本**应该是相同的.实际的答案不是相同的文本,并且有些不同 - 虽然我也认识到它将写在实现的文档中我也注意到这些也被解释了(我使用过的大多数或所有编译器) . (3认同)

riderBill.. 14

谢谢你的回答,特别是.Adam Stelmaszczyk和piCookie,以及aib.

像许多程序员一样,我使用了非常规的使用"myApp.hpp"表单的应用程序特定文件,以及<libHeader.hpp>库和编译器系统文件的表单,即/IINCLUDE环境变量中指定的文件,多年来认为是标准.

但是,C标准规定搜索顺序是特定于实现的,这会使可移植性变得复杂.更糟糕的是,我们使用jam,它可以自动计算包含文件的位置.您可以为包含文件使用相对路径或绝对路径.即

#include "../../MyProgDir/SourceDir1/someFile.hpp"

较旧版本的MSVS需要双反斜杠(\\),但现在不需要.我不知道它什么时候改变了.只需使用正斜杠与'nix兼容(Windows会接受).

如果你真的很担心它,请"./myHeader.h"在与源代码相同的目录中使用包含文件(我当前的非常大的项目有一些重复的包含文件名分散 - 实际上是一个配置管理问题).

以下是为方便起见而复制的MSDN说明.

引用形式

预处理器按以下顺序搜索包含文件:

  1. 与包含#include语句的文件位于同一目录中.
  2. 在当前打开的包含文件的目录中,按照打开
    它们的相反顺序.搜索从父包含文件的目录开始,并
    继续向上遍历任何祖父包含文件的目录.
  3. 沿着每个/I编译器选项指定的路径.
  4. 沿着INCLUDE环境变量指定的路径.

角括号形式

预处理器按以下顺序搜索包含文件:

  1. 沿着每个/I编译器选项指定的路径.
  2. 在命令行上进行编译时,沿INCLUDE环境变量指定的路径进行编译.


大智慧.. 13

至少对于GCC版本<= 3.0,角括号形式不会在包含文件和包含文件之间产生依赖关系.

因此,如果要生成依赖关系规则(使用GCC -M选项作为示例),则必须使用引用的表单来存储应该包含在依赖关系树中的文件.

(见http://gcc.gnu.org/onlinedocs/cpp/Invocation.html)


Maxim Egorus.. 12

对于#include ""编译器,通常会搜索包含该文件的文件夹,然后搜索其他文件夹.对于#include <>编译器不搜索当前文件的文件夹.


Adrian Zhang.. 12

#include <file.h>告诉编译器在其"includes"目录中搜索头文件,例如编译器将file.h在C:\ MinGW\include \或编译器安装位置搜索的MinGW.

#include "file"告诉编译器搜索当前目录(即源文件所在的目录)file.

您可以使用-IGCC 的标志告诉它,当它遇到包含斜角括号的包含时,它还应该在之后搜索目录中的标题-I.GCC会将标志后的目录视为includes目录.

例如,如果您myheader.h在自己的目录中调用了一个文件,则可以说#include <myheader.h>是否使用该标志调用GCC -I .(表示它应该在当前目录中搜索包含.)

如果没有该-I标志,则必须使用#include "myheader.h"包含该文件,或者移动myheader.hinclude编译目录.


MobiDev.. 11

  • #include <> 用于预定义的头文件

如果头文件是预定义的,那么你只需在尖括号中编写头文件名,它就像这样(假设我们有一个预定义的头文件名iostream):

#include <iostream>
  • #include " " 是程序员定义的头文件

如果您(程序员)编写了自己的头文件,那么您可以在引号中编写头文件名.因此,假设您编写了一个名为的头文件myfile.h,那么这是一个如何使用include指令包含该文件的示例:

#include "myfile.h"


Damon.. 9

带有尖括号的#include将搜索要包含的文件的"依赖于实现的位置列表"(这是一种非常复杂的说"系统头"的方式).

带引号的#include将只搜索文件(并且,"以依赖于实现的方式",bleh).这意味着,在普通英语中,它将尝试应用您在其上投掷的路径/文件名,并且不会预先添加系统路径或以其他方式篡改它.

此外,如果#include""失败,则标准将其重新读为#include <>.

海湾合作委员会的文件有一个(编译器特定的)描述,虽然是专门针对gcc和不标准,是一个更容易比的ISO标准的律师式的交谈,了解.


大智慧.. 9

当您使用#include <filename>时,预处理器在C\C++头文件(stdio.h\cstdio,string,vector等)的目录中查找文件.但是,当你使用#include"filename"时:首先,预处理器在当前目录中查找文件,如果它不在这里 - 他在C\C++头文件目录中查找它.


大智慧.. 8

#include "filename" // User defined header
#include <filename> // Standard library header.

例:

这里的文件名是Seller.h:

#ifndef SELLER_H     // Header guard
#define SELLER_H     // Header guard

#include <string>
#include <iostream>
#include <iomanip>

class Seller
{
    private:
        char name[31];
        double sales_total;

    public:
        Seller();
        Seller(char[], double);
        char*getName();

#endif

在类实现中(例如,Seller.cpp在将使用该文件的其他文件中Seller.h),现在应该包括用户定义的标头,如下所示:

#include "Seller.h"


sp2danny.. 8

这里的许多答案都集中在编译器为了找到文件而搜索的路径上.虽然这是大多数编译器所做的,但是允许符合标准的编译器使用标准头的效果进行预编程,并且可以将其#include <list>视为交换机,并且它根本不需要作为文件存在.

这不是纯粹的假设.至少有一个编译器以这种方式工作.使用#include <xxx>建议只用标准的头.


Christy Wald.. 8

#include <abc.h>

用于包括标准库文件.因此,编译器将检查标准库头所在的位置.

#include "xyz.h"

将告诉编译器包含用户定义的头文件.因此编译器将检查当前文件夹或已-I定义文件夹中的这些头文件.


大智慧.. 6

在C++中,以两种方式包含文件:

第一个是#include,它告诉预处理器在预定义的默认位置查找文件.此位置通常是INCLUDE环境变量,表示包含文件的路径.

第二种类型是#include"filename",它告诉预处理器首先在当前目录中查找文件,然后在用户设置的预定义位置查找它.


大智慧.. 6

"<filename>"在标准C库位置搜索

而"filename"也在当前目录中搜索.

理想情况下,您可以将<...>用于标准C库,将"..."用于您编写并存在于当前目录中的库.

  • 哪些新信息会将此答案添加到其他信息中? (2认同)

srsci.. 5

#include <filename>引用系统文件时使用.这是一个头文件,可以在系统默认位置找到,如/usr/include/usr/local/include.对于需要包含在另一个程序中的自己的文件,您必须使用#include "filename"语法.


归档时间:

查看次数:

480173 次

最近记录:

10 月,1 周 前