提问人:quest49 提问时间:8/22/2008 最后编辑:Mateen Ulhaqquest49 更新时间:8/11/2022 访问量:883783
#include < 文件名>和 #include“文件名”有什么区别?
What is the difference between #include <filename> and #include "filename"?
答:
不同的是预处理器搜索要包含的文件的位置。
#include <filename>
预处理器以实现定义的方式进行搜索,通常在编译器/IDE 预先指定的目录中进行搜索。此方法通常用于包含 C 标准库的头文件以及与目标平台关联的其他头文件。#include "filename"
预处理器还以实现定义的方式进行搜索,但通常用于包含程序员定义的头文件,并且通常包含与包含指令的文件相同的目录(除非给出了绝对路径)。
对于 GCC,有关搜索路径的 GCC 文档中提供了更完整的说明。
评论
<>
""
""
<>
include 告诉预处理器首先在目录和预定义目录中搜索,然后在 .c 文件的目录中搜索。include 告诉预处理器首先搜索源文件的目录,然后恢复到预定义。无论如何,都会搜索所有目的地,只是搜索顺序不同。<file>
-I
"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"
#include <file>
此外,存在第三种形式,当指令与上述任一形式不匹配时使用。在这种形式中,一些基本的预处理(如宏扩展)是在指令的“操作数”上完成的,结果应该与其他两种形式之一相匹配。#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:源字符集的任何成员,换行符和
"
评论
它确实:
"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"
#include <...>
/usr/include/mypath/myfile
/usr/include/./mypath/myfile
defaultincludepaths
.
#include "..."
#include <...>
对于编译器来说,通常会搜索包含该包含的文件的文件夹,然后搜索其他文件夹。因为编译器不搜索当前文件的文件夹。#include ""
#include <>
评论
<filename>
"filename"
带有尖括号的 #include 将搜索“与实现相关的位置列表”(这是“系统标头”的一种非常复杂的表示方式)以包含文件。
带引号的 #include 只会搜索一个文件(并且,“以依赖于实现的方式”,咩)。这意味着,在普通英语中,它将尝试应用您抛给它的路径/文件名,并且不会在系统路径之前添加或篡改它。
此外,如果 #include “” 失败,则会根据标准将其重新读取为 #include <>。
gcc 文档有一个(特定于编译器的)描述,尽管它特定于 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
Seller.h
#include "Seller.h"
至少对于 GCC 版本 <= 3.0,尖括号形式不会在包含的文件和包含的文件之间生成依赖关系。
因此,如果要生成依赖关系规则(例如使用 GCC -M 选项),则必须对应包含在依赖关系树中的文件使用带引号的表单。
(见 http://gcc.gnu.org/onlinedocs/cpp/Invocation.html )
评论
这里有一些很好的答案引用了 C 标准,但忘记了 POSIX 标准,尤其是 c99(例如 C 编译器)命令的特定行为。
根据 The Open Group Base Specifications Issue 7,
-I 目录
更改用于搜索名称不是绝对路径名的标头的算法,以便在查找通常位置之前在由目录路径名命名的目录中查找。因此,名称用双引号 ( “” ) 括起来的标头应首先在带有 #include 行的文件目录中搜索,然后在 -I 选项中命名的目录中搜索,最后在通常的位置搜索。对于名称用尖括号 ( “<>” 括起来的标头,应仅在 -I 选项中命名的目录中搜索,然后在通常的位置搜索。在 -I 选项中命名的目录应按指定的顺序进行搜索。在单个 c99 命令调用中,实现应支持此选项的至少 10 个实例。
因此,在符合 POSIX 的环境中,使用符合 POSIX 的 C 编译器,可能会首先搜索 where,where 是带有语句的文件的目录,而 ,可能会首先搜索,where 是您的系统定义的标头的通常位置(它似乎不是由 POSIX 定义的)。#include "file.h"
./file.h
.
#include
#include <file.h>
/usr/include/file.h
/usr/include
评论
c99
的 POSIX 规范中找到——这是 C 编译器的 POSIX 名称。(POSIX 2008 标准几乎不能引用 C11;2013 年对 POSIX 2008 的更新并没有改变它所引用的 C 标准。
-L
#include <>
用于预定义的头文件
如果头文件是预定义的,那么你只需将头文件名写在尖括号中,它看起来像这样(假设我们有一个预定义的头文件名 iostream):
#include <iostream>
#include “ ”
表示程序员定义的头文件
如果你(程序员)写了你自己的头文件,那么你就用引号写了头文件名。因此,假设您编写了一个名为 的头文件,那么这是如何使用 include 指令包含该文件的示例:myfile.h
#include "myfile.h"
评论
简单的一般规则是使用尖括号来包含编译器附带的头文件。使用双引号包含任何其他头文件。大多数编译器都是这样做的。
1.9 – 头文件更详细地解释了预处理器指令。如果你是一个新手程序员,该页面应该可以帮助你理解所有这些。我从这里学到了它,我一直在工作中遵循它。
这里的许多答案都集中在编译器为了查找文件而搜索的路径上。虽然这是大多数编译器所做的,但允许使用标准头文件的效果对符合要求的编译器进行预编程,并将其视为开关,并且根本不需要作为文件存在。#include <list>
这不是纯粹的假设。至少有一个编译器以这种方式工作。建议仅与标准标头一起使用。#include <xxx>
评论
#include "fname"
float.h
在引用系统文件时使用 。这是一个头文件,可以在系统默认位置找到,如 或 。对于需要包含在另一个程序中的您自己的文件,您必须使用语法。#include <filename>
/usr/include
/usr/local/include
#include "filename"
感谢您的精彩回答,尤其是 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
#include <filename>
当您要使用 C/C++ 系统或编译器库的头文件时使用。这些库可以是 stdio.h、string.h、math.h 等。
#include "path-to-file/filename"
当您想要使用自己的自定义头文件(位于项目文件夹或其他位置)时,会使用。
有关预处理器和标头的详细信息。阅读 C - 预处理器。
按照标准 - 是的,它们是不同的:
表单的预处理指令
#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 <...>
评论
在 C++ 中,以两种方式包含文件:
第一个是 #include 它告诉预处理器在预定义的默认位置查找文件。 此位置通常是一个 INCLUDE 环境变量,表示包含文件的路径。
第二种类型是 #include“文件名”,它告诉预处理器首先在当前目录中查找文件,然后在用户设置的预定义位置查找它。
GCC 文档对两者之间的区别进行了如下说明:
用户和系统头文件都使用预处理指令
“#include”
包含在内。它有两种变体:
#include <file>
此变体用于系统头文件。它在系统目录的标准列表中搜索名为 file 的文件。您可以使用以下选项将目录附加到此列表前面(请参阅调用)。
-I
#include "file"
此变体用于您自己程序的头文件。它首先在包含当前文件的目录中搜索名为 file 的文件,然后在 quote 目录中搜索,最后在用于 的相同目录中搜索 。您可以使用该选项将目录附加到报价目录列表的前面。 的参数,无论是用引号还是尖括号分隔,其行为都类似于字符串常量,因为无法识别注释,并且不会展开宏名称。因此,指定包含名为 的系统头文件。
<file>
-iquote
‘#include’
#include <x/*y>
x/*y
但是,如果反斜杠出现在文件中,则它们被视为普通文本字符,而不是转义字符。不处理任何适合 C 中字符串常量的字符转义序列。因此,指定包含三个反斜杠的文件名。(某些系统将“\”解释为路径名分隔符。所有这些也以同样的方式解释。它是最便携的,只能使用。
#include "x\n\\y"
‘/’
‘/’
如果文件名后面的行上有任何内容(注释除外),则为错误。
评论
#include
#include "foo.h"
#include <bar.h>
#include <abc.h>
用于包含标准库文件。因此,编译器将签入标准库头文件所在的位置。
#include "xyz.h"
将告诉编译器包含用户定义的头文件。因此,编译器将在当前文件夹或定义的文件夹中检查这些头文件。-I
预处理器的确切行为因编译器而异。以下答案适用于 GCC 和其他几个编译器。
#include <file.h>
告诉编译器在其“includes”目录中搜索标头,例如,编译器将在 C:\MinGW\include\ 或编译器安装的任何位置搜索 MinGW。file.h
#include "file"
指示编译器在当前目录(即源文件所在的目录)中搜索 。file
您可以使用 GCC 的标志来告诉它,当它遇到带尖括号的包含时,它还应该在 之后的目录中搜索标头。GCC 会将标志后面的目录视为目录。-I
-I
includes
例如,如果你在自己的目录中调用了一个文件,你可以说你是否调用了带有标志的 GCC(表示它应该在当前目录中搜索 includes)。myheader.h
#include <myheader.h>
-I .
如果没有该标志,则必须使用该标志来包含文件,或移动到编译器的目录。-I
#include "myheader.h"
myheader.h
include
评论
“<文件名>”在标准 C 库位置进行搜索
而“filename”也在当前目录中搜索。
理想情况下,您会使用<...>标准 C 库和“...”对于您编写并存在于当前目录中的库。
评论
表格 1 - #include < xxx >
首先,在调用指令的当前目录中查找头文件是否存在。如果未找到,则在标准系统目录的预配置列表中进行搜索。
表格 2 - #include “xxx”
这将在调用指令的当前目录中查找头文件是否存在。
确切的搜索目录列表取决于目标系统、GCC 的配置方式以及安装位置。 您可以通过使用 -v 选项运行它来找到 GCC 编译器的搜索目录列表。
您可以使用 - I dir 将其他目录添加到搜索路径中,这会导致在当前目录(对于指令的引号形式)之后和标准系统目录之前搜索dir。
基本上,“xxx”形式只不过是在当前目录中搜索;如果未找到,则回退表单
评论
#include "header.h"
有两种方法可以编写 #include 语句。这些是:
#include"filename"
#include<filename>
每种形式的含义是
#include"mylib.h"
此命令将在当前目录中查找文件,以及可能已设置的包含搜索路径中提到的指定目录列表。mylib.h
#include<mylib.h>
此命令将仅在指定的目录列表中查找文件。mylib.h
包含搜索路径只不过是要搜索要包含的文件的目录列表。不同的 C 编译器允许您以不同的方式设置搜索路径。
评论
#include
要使用 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:Library/Developer/CommandLineTools/usr/bin
“/Library/Developer/CommandLineTools/usr/bin/clang” -cc1 -triple x86_64-apple-macosx10.14.0-Wdeprecated-objc-isa-usage -Werror=已弃用的objc-isa-usage-E-禁用免费-disable-llvm-验证者-discard-value-names-main-file-namenull -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 /资源库/Developer/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 - -x c /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 /Library/Developer/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 (框架 directory)
搜索列表末尾。
#include <filename>
- 预处理器以与实现相关的方式进行搜索。它告诉编译器搜索保存系统头文件的目录。
- 此方法通常用于查找标准头文件。
#include "filename"
- 这告诉编译器搜索运行程序的头文件。如果失败,它的行为类似于在存储系统头文件的位置搜索该头文件。
#include <filename>
- 该方法通常用于识别用户定义的头文件(由用户创建的头文件)。如果您想调用标准库,请不要使用它,因为它比 .
#include <filename>
#include <file>
包括默认包含目录所在的文件。
#include "file"
包括编译该文件的当前目录中的文件。双引号也可以指定不同位置的完整文件路径。
通常,区别在于预处理器搜索头文件的位置:
#include 是包含头文件的预处理器指令。这两个 #include 都用于在程序中添加或包含头文件,但首先是包含系统头文件,然后是用户定义的头文件。
- #include < filename> 用于在程序中包含系统库头文件,表示 C/C++ 预处理器将搜索存储 C 库文件或存储预定义系统头文件的文件名。
- #include“filename”用于在程序中包含用户定义的头文件,则表示 C/C++ 预处理器将在程序所在的当前目录中搜索文件名,然后遵循用于 #include < filename 的搜索路径>
查看 gcc 文档 gcc include 文件
""
将首先搜索。然后搜索默认包含路径。
您可以使用如下命令来打印默认的包含路径:./
gcc -v -o a a.c
以下是一些示例,可以使事情更清楚: 代码 A.C 有效
// a.c
#include "stdio.h"
int main() {
int a = 3;
printf("a = %d\n", a);
return 0;
}
公元前的代码也有效
// b.c
#include <stdio.h>
int main() {
int a = 3;
printf("a = %d\n", a);
return 0;
}
但是当我创建一个在当前目录中命名的新文件时stdio.h
// stdio.h
inline int foo()
{
return 10;
}
a.c
将生成编译错误,但仍然有效b.c
和 “”,<>可以与相同的文件名一起使用。由于搜索路径优先级不同。
所以也有效d.c
// d.c
#include <stdio.h>
#include "stdio.h"
int main()
{
int a = 0;
a = foo();
printf("a=%d\n", a);
return 0;
}
编译器生成的实现定义的警告可以(并且将)以不同的方式对待系统库和程序库。
所以
#include <myFilename>
-- 这实际上声明了 myFilename 位于系统库位置 -- 可能(并且可能会)隐藏死代码和未使用的变量警告等,当您使用时会显示:
#include "myFilename"
评论
#include
#include
/external:anglebrackets
评论