在C和C++编程语言中,使用尖括号和在include
语句中使用引号有什么区别,如下所示?
#include
#include "filename"
quest49.. 1306
实际上,差异在于预处理器搜索包含文件的位置.
对于#include
预处理器以依赖于实现的方式搜索,通常在编译器/ IDE预先指定的搜索目录中.此方法通常用于包括标准库头文件.
对于#include "filename"
预处理器首先在与包含该指令的文件相同的目录中进行搜索,然后按照用于#include
表单的搜索路径进行搜索.此方法通常用于包括程序员定义的头文件.
有关搜索路径的GCC 文档中提供了更完整的描述.
实际上,差异在于预处理器搜索包含文件的位置.
对于#include
预处理器以依赖于实现的方式搜索,通常在编译器/ IDE预先指定的搜索目录中.此方法通常用于包括标准库头文件.
对于#include "filename"
预处理器首先在与包含该指令的文件相同的目录中进行搜索,然后按照用于#include
表单的搜索路径进行搜索.此方法通常用于包括程序员定义的头文件.
有关搜索路径的GCC 文档中提供了更完整的描述.
唯一的方法是阅读您的实现文档.
在C标准中,第6.10.2节第2至4段规定:
表单的预处理指令
#includenew-line 搜索的用于实现定义的地方的序列报头由之间的指定序列唯一地识别
<
和>
分隔符,并且使得由所述的全部内容替换该指令的标头.如何指定场所或标识的头是实现定义的.表单的预处理指令
#include "q-char-sequence" new-line导致由分隔符之间的指定序列标识的源文件的全部内容替换该指令
"
.以实现定义的方式搜索指定的源文件.如果不支持此搜索,或者搜索失败,则会重新处理该指令,就像它读取一样#includenew-line 使用
>
原始指令中相同的包含序列(包括字符,如果有的话).表单的预处理指令
#include pp-tokens new-line(允许与前两种形式中的一种不匹配).
include
指令中的预处理标记处理与正常文本一样.(当前定义为宏名称的每个标识符将替换为其预处理标记的替换列表.)所有替换后生成的指令应与前两个表单中的一个匹配.将a<
和>
预处理令牌对或一对"
字符之间的一系列预处理标记组合成单个标题名称预处理标记的方法是实现定义的.
定义:
h-char:源字符集的任何成员,除了换行符和
>
q-char:源字符集的任何成员,除了换行符和
"
<和>之间的字符序列唯一地引用标题,该标题不一定是文件.实现几乎可以随意使用字符序列.(但是,大多数情况下,只需将其视为文件名并在包含路径中进行搜索,就像其他帖子所述.)
如果使用该#include "file"
表单,则实现首先查找给定名称的文件(如果支持).如果不是(支持),或者搜索失败,则实现的行为就像使用了other(#include
)形式一样.
此外,存在第三种形式,当#include
指令与上述任何一种形式都不匹配时使用.在这种形式中,一些基本的预处理(例如宏扩展)在#include
指令的"操作数"上完成,并且结果预期与其他两种形式中的一种匹配.
这里的一些好的答案引用了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
,可能/usr/include/file.h
首先搜索,/usr/include
系统定义在哪里通常的标题位置(似乎没有POSIX定义).
海湾合作委员会的文件说明了以下两者之间的区别:
使用预处理指令包含用户和系统头文件
‘#include’
.它有两个变种:
#include
此变体用于系统头文件.它在标准的系统目录列表中搜索名为file的文件.您可以使用
-I
选项将目录添加到此列表中(请参阅调用).
#include "file"
此变体用于您自己的程序的头文件.它首先在包含当前文件的目录中搜索名为file的文件,然后在quote目录中搜索,然后使用相同的目录
.您可以使用该
-iquote
选项将目录添加到报价目录列表中.‘#include’
无论是用引号还是尖括号分隔的参数,都表现为字符串常量,因为无法识别注释,并且不会扩展宏名称.因此,#include
指定包含名为的系统头文件x/*y
.但是,如果文件中出现反斜杠,则它们被视为普通文本字符,而不是转义字符.没有处理适合C中字符串常量的字符转义序列.因此,
#include "x\n\\y"
指定包含三个反斜杠的文件名.(有些系统将'\'解释为路径名分隔符.所有这些也都以‘/’
相同的方式解释.它最易于使用‘/’
.)如果文件名后面的行上有任何内容(注释除外),则会出错.
它确实:
"mypath/myfile" is short for ./mypath/myfile
用.
是其中所述文件的任一目录#include
被包含在,和/或编译器的当前工作目录,和/或default_include_paths
和
is short for /mypath/myfile
如果./
是
,那么它没有什么区别.
如果mypath/myfile
在另一个包含目录中,则行为未定义.
在
包括告诉预处理到搜索-I
目录和在预定义的目录第一,然后在.c文件的目录.在"file"
包括告诉预处理器搜索源文件的目录第一,然后恢复到-I
和预定义.无论如何都会搜索所有目的地,只有搜索顺序不同.
2011标准主要讨论"16.2源文件包含"中的包含文件.
2表单的预处理指令
# include
new-line 搜索一系列实现定义的位置,以查找由<和>分隔符之间的指定序列唯一标识的标头,并使标头的整个内容替换该指令.如何指定场所或标识的头是实现定义的.
3表单的预处理指令
# include "q-char-sequence" new-line
导致由"delimiters"之间的指定序列标识的源文件的全部内容替换该指令.以实现定义的方式搜索指定的源文件.如果不支持此搜索,或者搜索失败,该指令被重新处理,就像它读取一样
# include
new-line 使用原始指令中相同的包含序列(包括>字符,如果有的话).
请注意,如果找不到文件,"xxx"
表单会降级
.其余的是实现定义的.
按标准 - 是的,它们是不同的:
表单的预处理指令
#includenew-line 搜索一系列实现定义的位置,以查找由
<
和>
分隔符之间的指定序列唯一标识的标头,并使标头的整个内容替换该指令.如何指定场所或标识的头是实现定义的.表单的预处理指令
#include "q-char-sequence" new-line导致由
"
分隔符之间的指定序列标识的源文件的全部内容替换该指令.以实现定义的方式搜索指定的源文件.如果不支持此搜索,或者搜索失败,则会重新处理该指令,就像它读取一样#includenew-line 使用
>
原始指令中相同的包含序列(包括字符,如果有的话).表单的预处理指令
#include pp-tokens new-line(允许与前两种形式中的一种不匹配).
include
指令中的预处理标记处理与正常文本一样.(当前定义为宏名称的每个标识符将替换为其预处理标记的替换列表.)所有替换后生成的指令应与前两个表单中的一个匹配.将a<
和>
预处理令牌对或一对"
字符之间的一系列预处理标记组合成单个标题名称预处理标记的方法是实现定义的.
定义:
h-char:源字符集的任何成员,除了换行符和
>
q-char:源字符集的任何成员,除了换行符和
"
请注意,该标准没有说明实现定义方式之间的任何关系.第一种形式以一种实现定义的方式搜索,另一种以(可能是其他)实现定义的方式搜索.该标准还规定了某些包含文件应存在(例如
).
在形式上你必须阅读编译器的手册,但是通常(按照传统),#include "..."
表单会搜索#include
首先找到的文件的目录,然后#include <...>
搜索表单搜索的目录(包含路径,例如系统头文件) ).
谢谢你的回答,特别是.Adam Stelmaszczyk和piCookie,以及aib.
像许多程序员一样,我使用了非常规的使用"myApp.hpp"
表单的应用程序特定文件,以及
库和编译器系统文件的表单,即/I
在INCLUDE
环境变量中指定的文件,多年来认为是标准.
但是,C标准规定搜索顺序是特定于实现的,这会使可移植性变得复杂.更糟糕的是,我们使用jam,它可以自动计算包含文件的位置.您可以为包含文件使用相对路径或绝对路径.即
#include "../../MyProgDir/SourceDir1/someFile.hpp"
较旧版本的MSVS需要双反斜杠(\\),但现在不需要.我不知道它什么时候改变了.只需使用正斜杠与'nix兼容(Windows会接受).
如果你真的很担心它,请"./myHeader.h"
在与源代码相同的目录中使用包含文件(我当前的非常大的项目有一些重复的包含文件名分散 - 实际上是一个配置管理问题).
以下是为方便起见而复制的MSDN说明.
引用形式
预处理器按以下顺序搜索包含文件:
与包含#include语句的文件位于同一目录中.
在当前打开的包含文件的目录中,按照打开
它们的相反顺序.搜索从父包含文件的目录开始,并
继续向上遍历任何祖父包含文件的目录.沿着每个
/I
编译器选项指定的路径.沿着
INCLUDE
环境变量指定的路径.角括号形式
预处理器按以下顺序搜索包含文件:
沿着每个
/I
编译器选项指定的路径.在命令行上进行编译时,沿
INCLUDE
环境变量指定的路径进行编译.
#include
告诉编译器在其"includes"目录中搜索头文件,例如编译器将file.h
在C:\ MinGW\include \或编译器安装位置搜索的MinGW.
#include "file"
告诉编译器搜索当前目录(即源文件所在的目录)file
.
您可以使用-I
GCC 的标志告诉它,当它遇到包含斜角括号的包含时,它还应该在之后搜索目录中的标题-I
.GCC会将标志后的目录视为includes
目录.
例如,如果您myheader.h
在自己的目录中调用了一个文件,则可以说#include
是否使用该标志调用GCC -I .
(表示它应该在当前目录中搜索包含.)
如果没有该-I
标志,则必须使用#include "myheader.h"
包含该文件,或者移动myheader.h
到include
编译目录.
至少对于GCC版本<= 3.0,角括号形式不会在包含文件和包含文件之间产生依赖关系.
因此,如果要生成依赖关系规则(使用GCC -M选项作为示例),则必须使用引用的表单来存储应该包含在依赖关系树中的文件.
(见http://gcc.gnu.org/onlinedocs/cpp/Invocation.html)
对于#include ""
编译器,通常会搜索包含该文件的文件夹,然后搜索其他文件夹.对于#include <>
编译器不搜索当前文件的文件夹.
当您使用#include
带有尖括号的#include将搜索要包含的文件的"依赖于实现的位置列表"(这是一种非常复杂的说"系统头"的方式).
带引号的#include将只搜索文件(并且,"以依赖于实现的方式",bleh).这意味着,在普通英语中,它将尝试应用您在其上投掷的路径/文件名,并且不会预先添加系统路径或以其他方式篡改它.
此外,如果#include""失败,则标准将其重新读为#include <>.
在海湾合作委员会的文件有一个(编译器特定的)描述,虽然是专门针对gcc和不标准,是一个更容易比的ISO标准的律师式的交谈,了解.
#include <>
用于预定义的头文件
如果头文件是预定义的,那么你只需在尖括号中编写头文件名,它就像这样(假设我们有一个预定义的头文件名iostream):
#include
#include " "
是程序员定义的头文件
如果您(程序员)编写了自己的头文件,那么您可以在引号中编写头文件名.因此,假设您编写了一个名为的头文件myfile.h
,那么这是一个如何使用include指令包含该文件的示例:
#include "myfile.h"
#include "filename" // User defined header #include// Standard library header.
例:
这里的文件名是Seller.h
:
#ifndef SELLER_H // Header guard #define SELLER_H // Header guard #include#include #include class Seller { private: char name[31]; double sales_total; public: Seller(); Seller(char[], double); char*getName(); #endif
在类实现中(例如,Seller.cpp
在将使用该文件的其他文件中Seller.h
),现在应该包括用户定义的标头,如下所示:
#include "Seller.h"
这里的许多答案都集中在编译器为了找到文件而搜索的路径上.虽然这是大多数编译器所做的,但是允许符合标准的编译器使用标准头的效果进行预编程,并且可以将其#include
视为交换机,并且它根本不需要作为文件存在.
这不是纯粹的假设.至少有一个编译器以这种方式工作.使用#include
建议只用标准的头.
#include
用于包括标准库文件.因此,编译器将检查标准库头所在的位置.
#include "xyz.h"
将告诉编译器包含用户定义的头文件.因此编译器将检查当前文件夹或已-I
定义文件夹中的这些头文件.
在C++中,以两种方式包含文件:
第一个是#include,它告诉预处理器在预定义的默认位置查找文件.此位置通常是INCLUDE环境变量,表示包含文件的路径.
第二种类型是#include"filename",它告诉预处理器首先在当前目录中查找文件,然后在用户设置的预定义位置查找它.
"
"在标准C库位置搜索 而"filename"也在当前目录中搜索.
理想情况下,您可以将<...>用于标准C库,将"..."用于您编写并存在于当前目录中的库.
在#include
引用系统文件时使用.这是一个头文件,可以在系统默认位置找到,如/usr/include
或/usr/local/include
.对于需要包含在另一个程序中的自己的文件,您必须使用#include "filename"
语法.
首先,在调用伪指令的当前目录中查找头文件的存在。如果找不到,它将在标准系统目录的预配置列表中搜索。
这将在调用伪指令的当前目录中查找头文件的存在。
确切的搜索目录列表取决于目标系统,GCC的配置方式以及安装位置。您可以通过-v选项运行GCC编译器的搜索目录列表。
您可以使用-I dir将其他目录添加到搜索路径,这将导致在当前目录之后(对于指令的引用形式)在标准系统目录之前搜索dir。
基本上,“ xxx”的形式只不过是在当前目录中搜索;如果找不到,则退回表格