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

问:

在 include 指令中使用尖括号和引号有什么区别?

#include <文件名>

#include “文件名”

答1:

huntsbot.com全球7大洲远程工作机会,探索不一样的工作方式

不同的是预处理器搜索包含文件的位置。

#include 预处理器以与实现相关的方式搜索,通常在编译器/IDE 预先指定的搜索目录中。此方法通常用于包含标准库头文件。

#include “filename” 预处理器首先在与包含指令的文件相同的目录中搜索,然后按照用于#include 形式的搜索路径。此方法通常用于包含程序员定义的头文件。

GCC documentation on search paths 中提供了更完整的说明。

huntsbot.com提供全网独家一站式外包任务、远程工作、创意产品分享与订阅服务!

声明:“预处理器在同一目录中搜索......”在实践中可能是正确的,但标准规定命名的源文件是“以实现定义的方式搜索的”。请参阅 piCookie 的答案。

虽然您的答案可能看起来是“正确的”,因为这是按照惯例工作的实现数量,您应该仔细查看 aib 和 piCookie 的答案。他们都指出(由 C 标准的措辞支持)真正的区别是包含“头文件”与包含“源文件”(不,这并不意味着“.h”与“.h”。 C”)。在这种情况下,“源文件”可以是(通常是,而且几乎总是应该是)一个“.h”文件。标头不一定必须是文件(编译器可以例如包括静态编码的标头,而不是在文件中)。

“......预处理器在与正在编译的文件相同的目录中搜索要包含的文件。”这种说法并不完全正确。我对这个问题很感兴趣,因为我很好奇实际答案是什么,但我知道这不是真的,因为至少在 gcc 中,当您使用 -I 指定一个额外的包含路径时,它将搜索用 #include "filename.txt" 指定的文件。 H”

那些不喜欢这个答案的人,请举一个实际的例子,哪里错了。

“一个错误的实际例子”是无关紧要的。标准的存在是有原因的。准则(在标准中)是将 <> 用于实现中包含的标头,将 "" 用于其他所有内容。但很明显,这只是一个指导方针,这两种情况的搜索路径都是由实现定义的,除了 "" 如果找不到它会回退到 <> 之外。

答2:

打造属于自己的副业,开启自由职业之旅,从huntsbot.com开始!

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

在 the C standard 中,第 6.10.2 节第 2 至第 4 段指出:

#include new-line 形式的预处理指令在实现定义的位置序列中搜索由 < 和 > 分隔符之间的指定序列唯一标识的标头,并导致将该指令替换为标头的全部内容。如何指定位置或标识的标头是实现定义的。 #include “q-char-sequence” 换行符形式的预处理指令导致将该指令替换为由 " 分隔符之间的指定序列标识的源文件的全部内容。命名的源文件在实现定义的方式。如果不支持此搜索,或者如果搜索失败,则重新处理该指令,就好像它读取具有相同包含序列的 #include 换行符(包括 > 字符,如果any) 来自原始指令。允许使用 #include pp-tokens new-line 形式的预处理指令(与前两种形式之一不匹配)。指令中包含后的预处理标记与正常处理一样文本。(当前定义为宏名称的每个标识符都被其预处理标记的替换列表替换。)所有替换后产生的指令应匹配前两种形式之一。prepro 序列的方法在 < 和 > 预处理标记对或一对 " 字符之间处理标记被组合成单个标头名称 预处理标记是实现定义的。定义: h-char:源字符集的任何成员,除了换行符和 > q-char:源字符集的任何成员,除了换行符和 "

相关:在 g++ 和 visual c++ 中的实施

@piCookie 和 "filename" 都搜索实现定义的位置。那么区别是什么呢 ?

@Stefan,我只是引用了没有说明 INCLUDE_PATH 的标准。您的实现可能会这样做,而我的可能不会。最初的问题通常是 C 而不是专门的 gcc(我认为不使用 INCLUDE_PATH)或 Microsoft C(我认为这样做)或任何其他问题,因此无法笼统地回答,而是必须参考每个实现的文档。

与所有这些情况一样,具体示例(尤其是常见场景)非常有用且同样值得赞赏。不必要的迟钝通用答案没有太多实际用途。

“这就是 C 标准如何冗长而不回答您的问题”

答3:

与HuntsBot一起,探索全球自由职业机会–huntsbot.com

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

如果使用 #include “file” 形式,则实现首先查找给定名称的文件(如果支持)。如果不支持(支持),或者如果搜索失败,则实现的行为就像使用了其他 (#include ) 形式一样。

此外,当 #include 指令与上述任何一种形式都不匹配时,会使用第三种形式。在这种形式中,对 #include 指令的“操作数”进行了一些基本的预处理(例如宏扩展),并且预期结果与其他两种形式中的一种相匹配。

+1,这可能是这里最简洁和正确的答案。根据标准(piCookie 在他的回答中引用),唯一真正的区别是“标题”与“源文件”。无论哪种方式,搜索机制都是实现定义的。使用双引号意味着您打算包含一个“源文件”,而尖括号意味着您打算包含一个“标题”,正如您所说,它可能根本不是一个文件。

请参阅 Dan Moulding 对 quest49 答案的评论;标准头文件不必是文件形式,它们可以是内置的。

十年来,我一直在阅读“标准标题不必采用文件形式”。愿意提供一个真实的例子吗?

@Maxim Yegorushkin:我也想不出任何现有的现实世界的例子;但是,对于 MS-DOS,不存在完整的 C11 编译器,除非标头不必是文件。这是因为某些 C11 标头名称与“8.3”MS-DOS 文件名限制不兼容。

@MaximEgorushkin:VAX/VMS C 编译器将所有 C 运行时库头文件保存在单个文本库文件中(类似于 unix 存档),并使用 < 和 > 之间的字符串作为索引到图书馆。

答4:

huntsbot.com精选全球7大洲远程工作机会,涵盖各领域,帮助想要远程工作的数字游民们能更精准、更高效的找到对方。

这里的一些好的答案引用了 C 标准,但忘记了 POSIX 标准,尤其是 c99 (e.g. C compiler) 命令的具体行为。

根据The Open Group Base Specifications Issue 7,

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

因此,在符合 POSIX 的环境中,使用符合 POSIX 的 C 编译器,#include “file.h” 可能会首先搜索 ./file.h,其中 . 是包含 #include 语句的文件所在的目录,而 {5 },可能会首先搜索 /usr/include/file.h,其中 /usr/include 是您的系统为标题定义的常用位置(它似乎没有由 POSIX 定义)。

文本的确切来源是什么?它来自 IEEE Std 1003.1, 2013 的规范部分吗?

@osgx:在 POSIX 规范中可以找到 c99 的措辞(或极其相似的内容)——这是 C 编译器的 POSIX 名称。 (POSIX 2008 标准几乎不能引用 C11;2013 年对 POSIX 2008 的更新并没有改变它所引用的 C 标准。)

这也是我的第一个想法。 gcc 的手册页和其他人一样包含此内容。库也有类似的东西 - -L。

答5:

与HuntsBot一起,探索全球自由职业机会–huntsbot.com

预处理器的确切行为因编译器而异。以下答案适用于 GCC 和其他几个编译器。

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

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

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

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

如果没有 -I 标志,您将不得不使用 #include “myheader.h” 来包含文件,或者将 myheader.h 移动到编译器的 include 目录。

太疯狂了,很少有人(包括我自己)了解 C/C++ 开发的基本知识。记录不充分的公约的暴政。

答6:

huntsbot.com精选全球7大洲远程工作机会,涵盖各领域,帮助想要远程工作的数字游民们能更精准、更高效的找到对方。

GCC documentation says下面说说两者的区别:

使用预处理指令“#include”包含用户和系统头文件。它有两个变体: #include 这个变体用于系统头文件。它在系统目录的标准列表中搜索名为 file 的文件。您可以使用 -I 选项将目录添加到此列表中(请参阅调用)。 #include “file” 此变体用于您自己程序的头文件。它首先在包含当前文件的目录中搜索名为 file 的文件,然后在引用目录中搜索,然后在用于 的相同目录中搜索。您可以使用 -iquote 选项将目录添加到引用目录列表中。 ‘#include’ 的参数,无论是用引号还是尖括号分隔,都表现得像一个字符串常量,因为无法识别注释,也不会扩展宏名称。因此,#include 指定包含名为 x/*y 的系统头文件。但是,如果文件中出现反斜杠,则它们被视为普通文本字符,而不是转义字符。不处理任何适用于 C 中字符串常量的字符转义序列。因此,#include “x\n\y” 指定包含三个反斜杠的文件名。 (一些系统将“\”解释为路径名分隔符。所有这些也以相同的方式解释“/”。仅使用“/”是最便携的。)如果有任何内容(除了注释)是错误的文件名后面的行。

一个优秀的自由职业者,应该有对需求敏感和精准需求捕获的能力,而huntsbot.com提供了这个机会

什么是“报价目录”?

@JackM • 有 3 个位置:#include-ing 文件的 当前目录、引用目录(检查 #include "foo.h" 样式的路径包括)和系统目录(检查 #include 样式的路径包括)。

短语“系统头文件”中的“系统”是什么意思?我发现计算机科学家经常使用“系统”这个词,而我经常分不清它是指“操作系统”、“计算机系统”还是其他什么意思。

这是最好的答案。这个话题可以无限地讨论多年和几十年,但明显的编译器趋势是 <> 用于系统头文件,而“”用于本地目录和项目头文件。我将 <> 用于系统标题,将“”用于其他所有内容。这样,在代码中就可以清楚地知道标头是否是系统标头。另外,这样,如果您在更改代码时将本地项目标头移动到不同的目录,则无需将“”更改为 <>,反之亦然。 (PS:这也是 ReSharper C++ 方法,自动为您包含标题)。

我同意这是最好的答案。为了澄清起见,对我来说,系统文件是您没有编写的任何内容,并且正在引用,当然您的编译器包括,但除此之外任何其他已安装的软件包。还有你写的程序文件。使用 Google protobufs,系统文件将是 ,程序文件将是您的 protobuf“mydir/my_pb.h”。

答7:

HuntsBot周刊–不定时分享成功产品案例,学习他们如何成功建立自己的副业–huntsbot.com

它确实:

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

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

 is short for /mypath/myfile

如果 ./ 在 <default_include_paths> 中,则没有任何区别。

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

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

@Keith Thompson:没错,我在想我的 Linux 机器。显然它可能会有所不同。尽管在实践中,Windows 作为非 Posix 操作系统也确实将 / 解释为路径分隔符,并且 ./ 也存在。

然后 -L dirpath 选项将 dirpath 添加到 defaultincludepaths,而不是赋予 . 另一个含义(如上所述)。这具有预期的结果,即 #include "..." 和 #include <...> 在 dirpath 中搜索

我认为这个答案是不正确的,因为它意味着始终在当前工作目录中查找包含双引号的标头。搜索机制更加详细;这个答案不完整。我添加此评论不是为了抱怨或抱怨,而是因为系统要求我添加评论以解释我为什么拒绝此答案。

答8:

huntsbot.com – 程序员副业首选,一站式外包任务、远程工作、创意产品分享订阅平台。

包含告诉预处理器在 -I 目录和预定义目录中搜索首先,然后在 .c 文件的目录中搜索。 “file” 包含告诉预处理器搜索源文件的目录首先,然后恢复到 -I 和预定义。无论如何都会搜索所有目的地,只是搜索顺序不同。

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

形式为 #include 换行符的预处理指令在一系列实现定义的位置中搜索由 < 和 > 分隔符之间的指定序列唯一标识的标头,并导致替换该指令通过标题的全部内容。如何指定位置或标识的标头是实现定义的。 3 形式为 #include “q-char-sequence” 换行符的预处理指令导致将该指令替换为由 " 分隔符之间的指定序列标识的源文件的全部内容。搜索命名的源文件以实现定义的方式。如果不支持此搜索,或者搜索失败,则重新处理该指令,就好像它读取 #include 具有相同包含序列的换行符(包括 > 字符,如果有的话)来自原始指令。

请注意,如果找不到文件,“xxx” 形式会降级为 形式。其余的是实现定义的。

huntsbot.com全球7大洲远程工作机会,探索不一样的工作方式

您能否提供一个参考,说明此 -I 业务在 C 标准中的何处指定?

我看不到对 -I 的引用。

那是“实现定义的”部分。

“反正所有的目的地都搜索过了,只是搜索的顺序不同。”如果我尝试用 mingw 编译我的程序,如果我用 < > 包含它,它怎么会找不到我的头文件,但是用“”它确实找到了它。

答9:

与HuntsBot一起,探索全球自由职业机会–huntsbot.com

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

#include new-line 形式的预处理指令在实现定义的位置序列中搜索由 < 和 > 分隔符之间的指定序列唯一标识的标头,并导致将该指令替换为标头的全部内容。如何指定位置或标识的标头是实现定义的。 #include “q-char-sequence” 换行符形式的预处理指令导致将该指令替换为由 " 分隔符之间的指定序列标识的源文件的全部内容。命名的源文件在一种实现定义的方式。如果不支持此搜索,或者如果搜索失败,则重新处理指令,就好像它读取具有相同包含序列的 #include 换行符(包括 > 字符,如果any) 来自原始指令。允许使用 #include pp-tokens new-line 形式的预处理指令(与前两种形式之一不匹配)。指令中包含后的预处理标记与正常处理一样文本。(当前定义为宏名称的每个标识符都被其预处理标记的替换列表替换。)所有替换后产生的指令应匹配前两种形式之一。prepro 序列的方法在 < 和 > 预处理标记对或一对 " 字符之间处理标记被组合成单个标头名称 预处理标记是实现定义的。定义: h-char:源字符集的任何成员,除了换行符和 > q-char:源字符集的任何成员,除了换行符和 "

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

正式地,您必须阅读编译器的手册,但是通常(按照传统)#include “…” 形式首先搜索找到 #include 的文件的目录,然后搜索 #include <…> 形式的目录搜索(包含路径,例如系统头文件)。

huntsbot.com高效搞钱,一站式跟进超10+任务平台外包需求

这与 piCookie 七年前的回答基本相同。

@KyleStrand 那是因为相同的文本是标准中相关部分的引用 - 该文本应该是相同的。实际答案不是相同的文本,并且有些不同 - 虽然我也认识到它将写入实现的文档中,但我还注意到还有一种传统的解释方式(我使用的大多数或所有编译器都尊重) .

IMO 这是这里最好的答案,因为它既涵盖了标准的内容,也涵盖了大多数编译器的实际操作。

答10:

huntsbot.com全球7大洲远程工作机会,探索不一样的工作方式

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

因此,如果要生成依赖关系规则(例如使用 GCC -M 选项),则必须对应包含在依赖关系树中的文件使用带引号的形式。

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

是的 - 有几种不同的方式来生成依赖项。这是其中之一,但不是唯一的。

答11:

huntsbot.com精选全球7大洲远程工作机会,涵盖各领域,帮助想要远程工作的数字游民们能更精准、更高效的找到对方。

感谢您的精彩回答,尤其是。 Adam Stelmaszczyk 和 piCookie 和 aib。

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

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

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

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

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

为方便起见,这里复制了 MSDN explanation)。

引用形式 预处理器按以下顺序搜索包含文件: 在与包含#include 语句的文件相同的目录中。在当前打开的包含文件的目录中,按照打开它们的相反顺序。搜索从父包含文件的目录开始,并继续向上通过任何祖父包含文件的目录。沿着每个 /I 编译器选项指定的路径。沿着 INCLUDE 环境变量指定的路径。尖括号形式 预处理器按以下顺序搜索包含文件: 沿着每个 /I 编译器选项指定的路径。在命令行上进行编译时,沿着 INCLUDE 环境变量指定的路径。

原文链接:https://www.huntsbot.com/qa/bLb9/what-is-the-difference-between-include-filename-and-include-filename?lang=zh_CN&from=csdn

huntsbot.com – 高效赚钱,自由工作

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
#include <iostream> #include <fstream> 是C++中用于文件操作的库。其中,<iostream>包含了对标准输入输出流的定义,<fstream>包含了对文件输入输出流的定义。 如果想要打开一个文件并进行读写操作,可以使用以下语句: ```c++ std::fstream file("filename", std::ios::in | std::ios::out); ``` 其中,"filename"为文件名,std::ios::in表示打开文件进行读操作,std::ios::out表示打开文件进行写操作。如果需要同时进行读写操作,则可以使用std::ios::in | std::ios::out来进行指定。 如果需要只进行读操作,可以使用以下语句: ```c++ std::ifstream file("filename"); ``` 其中,std::ifstream表示只进行文件的读操作。 如果需要只进行写操作,可以使用以下语句: ```c++ std::ofstream file("filename"); ``` 其中,std::ofstream表示只进行文件的写操作。 在进行文件操作时,需要注意文件是否成功打开。可以使用以下代码来进行判断: ```c++ if(file.is_open()){ // 文件已经成功打开,可以进行读写操作 }else{ // 文件打开失败 } ``` 如果文件打开成功,则可以使用file对象进行读写操作。例如,可以使用以下代码来读取文件中的内容: ```c++ std::string line; while(std::getline(file, line)){ std::cout << line << std::endl; } ``` 这段代码会逐行读取文件中的内容,并将每行内容输出到控制台上。 如果需要向文件中写入内容,则可以使用以下代码: ```c++ file << "Hello, World!" << std::endl; ``` 这段代码会向文件中写入一行字符串"Hello, World!",并在末尾加上一个换行符。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值