在C和C ++编程语言中,在include
语句中使用尖括号和引号有什么区别,如下所示?
#include <filename>
#include "filename"
在C和C ++编程语言中,在include
语句中使用尖括号和引号有什么区别,如下所示?
#include <filename>
#include "filename"
Answers:
实际上,区别在于预处理器搜索包含文件的位置。
对于#include <filename>
预处理器,以依赖于实现的方式进行搜索,通常在由编译器/ IDE预先指定的搜索目录中进行。此方法通常用于包括标准库头文件。
对于#include "filename"
预处理程序,首先在与包含指令的文件相同的目录中搜索,然后遵循用于#include <filename>
表单的搜索路径。此方法通常用于包括程序员定义的头文件。
#include <...>
使用系统上安装的软件包并#include "..."
使用附近的存储库版本。我可能会倒退。无论哪种方式,打包标头中的include防护都带有下划线前缀。(这可能是软件包的约定,或者是一种有意避免两者混用的方法,尽管版本限定符对我而言更有意义。)
唯一知道的方法是阅读实现的文档。
在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
伪指令中的预处理令牌与普通文本一样进行处理。(当前定义为宏名称的每个标识符都将替换为其预处理令牌的列表。)所有替换后产生的指令应与前两种形式之一匹配。实现方法定义了一种方法,通过该方法,将<
和>
预处理令牌对之间的一系列预处理令牌或一对"
字符组合为单个标头名称预处理令牌。定义:
h-char:源字符集的任何成员,除了换行符和
>
q-char:源字符集的任何成员,除了换行符和
"
<和>之间的字符序列唯一地指的是标头,不一定是文件。实现几乎可以随意使用它们的字符序列。(但是,大多数情况下,只需将其视为文件名,然后在包含路径中进行搜索即可在其他帖子中声明。)
如果使用了#include "file"
表单,则实现将首先查找具有给定名称的文件(如果支持)。如果(不受支持)或搜索失败,则该实现的行为就像另一个(#include <file>
)形式。
另外,存在第三种形式,当#include
指令与以上两种形式都不匹配时,将使用第三种形式。在这种形式中,对#include
指令的“操作数”进行了一些基本的预处理(例如宏扩展),并且预期结果将与其他两种形式之一匹配。
<
和>
作为键来索引到库中。
这里有一些很好的答案引用了C标准,但忘记了POSIX标准,尤其是c99(例如C编译器)命令的特定行为。
根据开放团体基本规范第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似乎未定义)。
c99
这是C编译器的POSIX名称。(POSIX 2008标准几乎无法引用C11; 2013年对POSIX 2008的更新并未更改其引用的C标准。)
-L
。
使用预处理指令包括用户和系统头文件
‘#include’
。它有两个变体:
#include <file>
此变体用于系统头文件。它在系统目录的标准列表中搜索名为file的文件。您可以使用
-I
选项在目录之前添加目录(请参阅调用)。
#include "file"
此变体用于您自己程序的头文件。它首先在包含当前文件的目录中搜索一个名为file的文件,然后在引号目录中搜索,然后在中使用相同的目录
<file>
。您可以使用-iquote
选项将目录放在报价目录列表的前面。的论点‘#include’
用引号或尖括号分隔)的行为类似于字符串常量,因为注释无法识别,宏名称也不会扩展。因此,#include <x/*y>
指定包含名为的系统头文件x/*y
。但是,如果文件中出现反斜杠,则将其视为普通文本字符,而不是转义字符。没有适合于C中字符串常量的字符转义序列被处理。从而,
#include "x\n\\y"
指定一个包含三个反斜杠的文件名。(某些系统将'\'解释为路径名分隔符。所有这些也以‘/’
相同的方式解释。仅可移植使用‘/’
。)如果文件名后面的行中有任何内容(注释除外),则错误。
它确实:
"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 <...>
。(实际上,它可能是等效的,但仅是因为,例如,至少在类似Unix的系统上,它/usr/include/mypath/myfile
可以被称为/usr/include/./mypath/myfile
。)
defaultincludepaths
,而不是给赋予了另一种含义.
(如上所述)。这样做的后果预期这两个#include "..."
和#include <...>
在搜索dirpath
在<file>
包括告诉预处理到搜索-I
目录和在预定义的目录第一,然后在.c文件的目录。在"file"
包括告诉预处理器搜索源文件的目录第一,然后恢复到-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>
窗体。其余的是实现定义的。
-I
中指定此业务的位置的参考?
-I
。
#include <file.h>
告诉编译器在其“包含”目录中搜索标头,例如,对于MinGW,编译器将file.h
在C:\ MinGW \ include \或安装了编译器的任何位置进行搜索。
#include "file"
告诉编译器在当前目录(即源文件所在的目录)中搜索file
。
您可以使用-I
GCC 的标志来告知它,当遇到带有尖括号的include时,它还应该在目录之后的标头中搜索-I
。GCC会将标志后的目录视为includes
目录。
例如,如果您myheader.h
在自己的目录中有一个名为的文件,则可以说#include <myheader.h>
是否使用带有标志的GCC来调用-I .
(表明该文件应在当前目录中搜索包含)。
如果没有该-I
标志,则必须使用它#include "myheader.h"
来包含文件,或移动myheader.h
到include
编译器的目录。
按照标准-是的,它们是不同的:
形式的预处理指令
#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 <...>
搜索该表单搜索的目录(包括路径,例如系统头) )。
特别是感谢您的出色回答。Adam Stelmaszczyk和piCookie,以及aib。
像许多程序员一样,我使用了非正式的约定,即将"myApp.hpp"
表单用于特定于应用程序的文件,并且<libHeader.hpp>
,即将表单用于库和编译器系统文件,即在中指定的文件/I
和INCLUDE
环境变量,多年来一直认为这是标准。
但是,C标准指出搜索顺序是特定于实现的,这会使可移植性变得复杂。更糟的是,我们使用jam来自动找出包含文件的位置。您可以为包含文件使用相对或绝对路径。即
#include "../../MyProgDir/SourceDir1/someFile.hpp"
较早版本的MSVS需要双反斜杠(\\),但现在不需要。我不知道什么时候变了。只需使用正斜杠即可与'nix兼容(Windows会接受)。
如果您真的很担心,请使用"./myHeader.h"
在与源代码相同的目录中一个包含文件(我当前的大型项目中有些重复的包含文件名分散存在,这确实是一个配置管理问题)。
为了方便起见,这里是MSDN解释复制在这里。
引用形式
预处理程序按以下顺序搜索包含文件:
- 与包含#include语句的文件位于同一目录中。
- 在当前打开的目录中,包含文件的顺序与
打开时相反。搜索从父包含文件的目录开始,然后
向上搜索所有祖父母包含文件的目录。- 沿着每个
/I
编译器选项指定的路径。- 沿
INCLUDE
环境变量指定的路径。角括号形式
预处理程序按以下顺序搜索包含文件:
- 沿着每个
/I
编译器选项指定的路径。- 当在命令行上进行编译时,将沿着
INCLUDE
环境变量指定的路径进行。
至少对于GCC版本<= 3.0,尖括号形式不会在包含的文件和包含的文件之间生成依赖关系。
因此,如果要生成依赖关系规则(例如,使用GCC -M选项),则必须对应包含在依赖关系树中的文件使用加引号的形式。
对于#include ""
编译器,通常先搜索包含以下内容的文件的文件夹,然后再搜索其他文件夹。对于#include <>
编译器,不搜索当前文件的文件夹。
<filename>
并"filename"
搜索实现定义的位置。
当您使用#include <filename>时,预处理器会在C \ C ++头文件的目录(stdio.h \ cstdio,字符串,向量等)中查找文件。但是,当您使用#include“ filename”时:首先,预处理器在当前目录中查找文件,如果不在此处,则在C \ C ++头文件目录中查找该文件。
#include
指令也与文件完全不相关。
带尖括号的#include将搜索“与实现相关的位置列表”(这是说“系统标题”的非常复杂的方式),以查找要包含的文件。
带引号的#include只会搜索文件(并且,“以与实现相关的方式”,等等)。这意味着,用普通的英语,它将尝试应用您扔给它的路径/文件名,并且不会在系统路径前添加或篡改它。
另外,如果#include“”失败,则标准会将其重新读取为#include <>。
在海湾合作委员会的文件有一个(编译器特定的)描述,虽然是专门针对gcc和不标准,是一个更容易比的ISO标准的律师式的交谈,了解。
zlib.h
在“用户”搜索路径中,并且系统搜索路径中存在其他版本,那么是否#include <zlib.h>
包括系统版本并#include "zlib.h"
包括我自己的版本?
#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
和在将使用file的其他文件中Seller.h
),现在应包括用户定义的标头,如下所示:
#include "Seller.h"
首先,在调用伪指令的当前目录中查找头文件的存在。如果找不到,它将在标准系统目录的预配置列表中搜索。
这将在调用伪指令的当前目录中查找头文件的存在。
确切的搜索目录列表取决于目标系统,GCC的配置方式以及安装位置。您可以通过-v选项运行GCC编译器的搜索目录列表。
您可以使用-I dir将其他目录添加到搜索路径,这将导致在当前目录之后(对于指令的引号形式)在标准系统目录之前搜索dir。
基本上,“ xxx”的形式只不过是在当前目录中搜索;如果找不到,则退回表格
#include "header.h"
表格描述不正确,@ personal_cloud。我认为piCookie和Yann Droneaud的答案最为相关,因为他们确定了信息的来源。我也不认为最受好评的答案也完全令人满意。
“ <filename>”在标准C库位置中搜索
而“文件名”也在当前目录中搜索。
理想情况下,对于标准C库,您可以使用<...>,对于您编写并存在于当前目录中的库,可以使用“ ...”。
简单的通用规则是使用尖括号包含编译器随附的头文件。使用双引号包括其他任何头文件。大多数编译器都是这样做的。
1.9 —头文件更详细地说明了预处理程序指令。如果您是新手程序员,那么该页面应该可以帮助您理解所有内容。我从这里学到了它,并且在工作中一直在关注它。
#include <filename>
当您要使用C / C ++系统的头文件或编译器库时使用。这些库可以是stdio.h,string.h,math.h等。
#include "path-to-file/filename"
当您要使用自己的自定义头文件时,该文件位于项目文件夹或其他位置。
有关预处理器和标头的更多信息。阅读C预处理程序。
要基于当前配置,使用gcc查看系统上的搜索顺序,可以执行以下命令。您可以在此处找到有关此命令的更多详细信息
cpp -v /dev/null -o /dev/null
Apple LLVM版本10.0.0(clang-1000.10.44.2)
目标:x86_64-apple-darwin18.0.0
线程模型:posix InstalledDir:库/开发人员/ CommandLineTools / usr / bin
“ / Library / Developer / CommandLineTools / usr / bin / clang” -cc1-三联x86_64-apple-macosx10.14.0 -Wdeprecated-objc-isa-usage -Werror = deprecated-objc-isa-usage -E -disable-free- disable-llvm-verifier -discard-value-names -main-file-name null -mrelocation-model pic -pic-level 2 -mthread-model posix -mdisable-fp-elim -fno-strict-return -masm-verbose- munwind-tables -target-cpu penryn -dwarf-column-info -debugger-tuning = lldb -target-linker-version 409.12 -v -resource-dir /Library/Developer/CommandLineTools/usr/lib/clang/10.0.0- isysroot /库/开发人员/CommandLineTools/SDKs/MacOSX10.14.sdk -I / usr / local / include -fdebug-compilation-dir / Users / hogstrom -ferror-limit 19 -fmessage-length 80 -stack-protector 1 -fblocks -fencode-extended-block-signature -fobjc-runtime = macosx-10.14。0 -fmax-type-align = 16 -fdiagnostics-show-option -fcolor-diagnostics -traditional-cpp -o--xc / dev / null
clang -cc1版本10.0.0(clang-1000.10.44.2)默认目标x86_64-apple-darwin18.0.0忽略不存在的目录“ /Library/Developer/CommandLineTools/SDKs/MacOSX10.14.sdk/usr/local/include”忽略不存在目录“ /Library/Developer/CommandLineTools/SDKs/MacOSX10.14.sdk/Library/Frameworks”
#include“ ...”搜索从此处开始:
#include <...>搜索从此处开始:
/ usr / local / include
/库/开发人员/CommandLineTools/usr/lib/clang/10.0.0/include /
Library / Developer / CommandLineTools / usr / include
/Library/Developer/CommandLineTools/SDKs/MacOSX10.14.sdk/usr/include
/ Library / Developer / CommandLineTools / SDKs / MacOSX10.14.sdk / System / Library / Frameworks(框架目录)
搜索列表的结尾。
有两种写#include语句的方法,它们是:
#include"filename"
#include<filename>
每种形式的含义是
#include"mylib.h"
此命令将mylib.h
在可能已设置的包含搜索路径中查找当前目录以及指定目录列表中的文件。
#include<mylib.h>
该命令将查找文件 mylib.h
仅在指定的目录列表中。
include搜索路径只不过是要搜索要包含的文件的目录列表。不同的C编译器允许您以不同的方式设置搜索路径。