提问



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



  1. #include <filename>

  2. #include "filename"


最佳参考


实际上,区别在于预处理器搜索包含文件的位置。


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


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


关于搜索路径的GCC文档中提供了更完整的描述。[135]

其它参考1


要知道的唯一方法是阅读您的实现文档。


在C标准第6.10.2节第2至4段中指出:[136]



  

      
  • 表单的预处理指令


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

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

  •   
  • 表单的预处理指令


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

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


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

      
      与原始相同的包含序列(包括>个字符,如果有的话)
      指示。

  •   
  • 表单的预处理指令


    #include pp-tokens new-line
    

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

  •   

  
  

解释


  
  

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

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

  •   


其它参考2


<之间的字符序列。和>唯一引用一个标题,它不一定是一个文件。实现可以随意使用字符序列。(但是,大多数情况下,只需将其视为文件名并在包含路径,正如其他帖子所述。)


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


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

其它参考3


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


根据The Open Group Base Specifications Issue 7,[138]



   -I 目录

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



因此,在POSIX兼容环境中,使用符合POSIX标准的C编译器,#include "file.h"可能首先搜索./file.h,其中.是具有[[.的文件的目录。虽然#include <file.h>可能会首先搜索/usr/include/file.h,但/usr/include是你的系统定义通常的地方标题(它是似乎没有定义POSIX)。

其它参考4


它确实:


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


.是包含#include的文件的目录,和/或编译器的当前工作目录,和/或default_include_paths





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


如果./<default_include_paths>中,那么它就没有区别。


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

其它参考5


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



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

  
  

    的 #include <file>

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

    
    的 #include "file"

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

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

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

  


其它参考6


<file> include告诉预处理器在-I目录和预定义目录 first 中搜索,然后在.c文件的目录中搜索。"file" include tell预处理器搜索源文件的目录第一个,然后恢复为-I并预定义。无论如何都要搜索所有目的地,只有搜索顺序不同。


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



  2表单的预处理指令

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

  
  搜索一系列实现定义的位置,以查找由唯一标识的标头
  <之间的指定序列和>分隔符,并导致
  用标题的全部内容替换该指令。
  如何指定地点或标识的标题是
  实现定义。

  
  3表单的预处理指令

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

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

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

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



请注意,如果找不到文件,"xxx"格式会降级为<xxx>格式。其余的是实现定义的。

其它参考7


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



  

      
  • 表单的预处理指令


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

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

  •   
  • 表单的预处理指令


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

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


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

      
      与原始相同的包含序列(包括>个字符,如果有的话)
      指示。

  •   
  • 表单的预处理指令


    #include pp-tokens new-line
    

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

  •   

  
  

解释


  
  

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

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

  •   



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


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

其它参考8


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


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


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


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


较旧版本的MSVS需要双反斜杠(\\\\),但现在不需要。我不知道它何时发生变化。只需使用正斜杠与nix兼容(Windows将接受)。


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


这里是为方便起见而复制的MSDN解释。[141]



  引用表单

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

  
  

      
  1. 与包含#include语句的文件位于同一目录中。

  2.   
  3. 在当前打开的包含文件的目录中,按照与
    相反的顺序
        他们被打开了。搜索从父包含文件和
    的目录开始
        继续向上通过任何祖父包含文件的目录。

  4.   
  5. 沿着每个/I编译器选项指定的路径。

  6.   
  7. 沿着INCLUDE环境变量指定的路径。

  8.   

  
  角括号表单

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

  
  

      
  1. 沿着每个/I编译器选项指定的路径。

  2.   
  3. 在命令行上进行编译时,沿着INCLUDE环境变量指定的路径进行编译。

  4.   


其它参考9


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


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


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

其它参考10


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

其它参考11



  • #include <>适用于预定义的标题文件



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


#include <iostream>



  • #include " "适用于程序员定义的头文件



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


#include "myfile.h"

其它参考12


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


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


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


gcc文档有一个(编译器特定的)描述虽然特定于gcc而不是标准,但比ISO标准的律师风格的讨论要容易理解。[143]

其它参考13


#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"

其它参考14


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

其它参考15


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


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

其它参考16


#include <file>告诉编译器在其包含目录中搜索标题,例如对于MinGW,编译器将在C:\\ MinGW \\ include \\或安装编译器的任何地方搜索file


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


您可以使用GCC的-I标志告诉它,当遇到包含斜角括号的包含时,它还应该在-I之后搜索目录中的标题。例如,如果你自己的目录中有一个名为myheader.h的文件,你可以说#include <myheader.h>如果用-I .调用GCC(表示它应该搜索当前目录中的包含)。 )如果没有-I标志,则必须使用#include "myheader.h"来包含文件,或将myheader.h移动到编译器的include目录中(参见上文)

其它参考17


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


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


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

其它参考18


#include <abc.h>


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


#include "xyz.h"


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

其它参考19



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

  
  而filename也在当前目录中搜索。



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

其它参考20


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

其它参考21


简单的一般规则是使用有角度的括号来包含编译器附带的头文件。使用双引号包含任何其他头文件。大多数编译器都是这样做的。


1.9 - 头文件更详细地解释了预处理器指令。如果您是新手程序员,该页面应该可以帮助您理解所有这些。我是从这里学到的,我一直在工作。[144]

其它参考22


#include <filename>

当您想要使用C/C ++系统或编译器库的头文件时使用。这些库可以是stdio.h,string.h,math.h等。


#include "path-to-file/filename"

当您想要使用项目文件夹中或其他位置的自定义头文件时使用。


有关预处理器和标头的更多信息。阅读 C - 预处理器。[145]

其它参考23


我相信包含在双引号中的标题将在相同的系统路径中查找,如果在当前目录中找不到它们,则包括angle-bracketed包含。

其它参考24


  #include <filename>   (1)     
  #include "filename"   (2)


#include包括由文件名标识的源文件到紧接在该指令之后的行的当前源文件中。



  该指令的第一个版本仅搜索标准包含
  目录。标准C ++库,以及标准C库,
  是暗示它包含在标准包含目录中。标准
  包含目录可以由用户通过编译器控制
  选项。

  
  第二个版本首先搜索当前文件所在的目录
  驻留,并且仅在未找到文件时才搜索标准
  包括目录。



如果找不到该文件,则该程序格式错误。

其它参考25


搜索头文件的顺序不同。 < XXX.h>首先搜索标准头,而XXX.h首先搜索工作空间的头文件。

其它参考26


#include <filename>


将从C ++库中找到相应的文件。
这意味着如果你在C ++库文件夹中有一个名为hello.h的文件,#include <hello.h>将加载它。


但,


#include "filename"


将在源文件所在的同一目录中找到该文件。


此外,


#include "path_to_file/filename"


将在path_to_file中键入的目录中找到该文件。

其它参考27


要包含预定义的库头文件,使用#include<filename>,而要包含用户定义的头文件,#include "filename"是相关的。