对于相同的预处理指令,这是一个多重问题.
除了在MSDN中找到的信息:
#include指令(C-C++)
1.a:两种符号之间有什么区别?
1.b:所有编译器都以同样的方式实现它们吗?
1.c:你什么时候使用<>,什么时候会使用""(即你用什么标准来使用一个或另一个标题包括在内)?
我已经看到至少有两种写作方式包括一个项目标题.考虑到您至少有4种类型的标题,即:
您项目的私有标题?
您的项目的标题,但导出符号(因此,"公共")
模块链接的另一个项目的标题
编译器或标准库的标头
对于每种标题:
2.a:你会用<>或""吗?
2.b:您是否只使用{TheProject/TheHeader.hpp}或{TheHeader.hpp}?
3.a:你是否在一个类似树的组织中使用源和/或标题的项目(即目录中的目录,而不是"一个目录中的每个文件"),有什么优点/缺点?
在阅读完所有答案以及编译器文档后,我决定遵循以下标准.
对于所有文件,无论是项目标题还是外部标题,始终使用模式:
#include
命名空间至少是一个目录深,以避免冲突.
当然,这意味着项目标题所在的项目目录也应该作为"default include header"添加到makefile中.
这个选择的原因是我找到了以下信息:
1.包含""模式依赖于编译器我将在下面给出答案
资源:
C++ 14 Working Draft n3797:https://isocpp.org/files/papers/N3797.pdf
C++ 11,C++ 98,C99,C89(引用的部分在所有这些标准中保持不变)
在16.2源文件包含部分中,我们可以读到:
表单的预处理指令
#includenew-line 搜索一系列实现定义的位置,以查找由<和>分隔符之间的指定序列唯一标识的标头,并使标头的整个内容替换该指令.如何指定场所或标识的头是实现定义的.
这意味着#include <...>将以实现定义的方式搜索文件.
然后,下一段:
表单的预处理指令
#include "q-char-sequence" new-line导致由"delimiters"之间的指定序列标识的源文件的全部内容替换该指令.以实现定义的方式搜索指定的源文件.如果不支持此搜索,或者搜索失败,该指令被重新处理,就像它读取一样
#includenew-line 使用原始指令中相同的包含序列(包括>字符,如果有的话).
这意味着#include"..."将以实现定义的方式搜索文件,然后,如果找不到该文件,将执行另一次搜索,就好像它是#include <...>
结论是我们必须阅读编译器文档.
请注意,由于某些原因,标准中没有任何地方在"系统"或"库"标题或其他标题之间进行区分.唯一的区别似乎#include <...>似乎是目标标题,而#include"..."似乎是目标来源(至少在英语措辞中).
资源:
http://msdn.microsoft.com/en-us/library/36k2cdd4.aspx
预处理器按以下顺序搜索包含文件:
与包含#include语句的文件位于同一目录中.
在任何先前打开的包含文件的目录中,按照打开它们的相反顺序.搜索从最后打开的包含文件的目录开始,并继续通过首先打开的包含文件的目录.
沿着每个/ I编译器选项指定的路径.
(*)沿INCLUDE环境变量指定的路径或开发环境默认包含.
预处理器按以下顺序搜索包含文件:
沿着每个/ I编译器选项指定的路径.
(*)沿INCLUDE环境变量指定的路径或开发环境默认包含.
该文档不清楚"沿着INCLUDE环境变量指定的路径"部分<...>
,"..."
包括.以下引用使其符合标准:
对于指定为#include"path-spec"的包含文件,目录搜索从父文件的目录开始,然后遍历任何祖父文件的目录.也就是说,搜索从包含源文件的目录开始,该源文件包含正在处理的#include指令.如果没有祖父文件并且找不到该文件,则继续搜索,就好像文件名用尖括号括起来一样.
因此,最后一步(用星号标记)是阅读整个文件的解释.
资源:
https://gcc.gnu.org/onlinedocs/cpp/Header-Files.html
https://gcc.gnu.org/onlinedocs/cpp/Include-Syntax.html
https://gcc.gnu.org/onlinedocs/cpp/Include-Operation.html
https://gcc.gnu.org/onlinedocs/cpp/Invocation.html
https://gcc.gnu.org/onlinedocs/cpp/Search-Path.html
https://gcc.gnu.org/onlinedocs/cpp/Once-Only-Headers.html
https://gcc.gnu.org/onlinedocs/cpp/Wrapper-Headers.html
https://gcc.gnu.org/onlinedocs/cpp/System-Headers.html
以下引用总结了该过程:
GCC [...]将
在[系统目录]中查找#include请求的头文件[...]在默认目录之前,按从左到右的顺序搜索-I命名的所有目录
GCC首先在包含当前文件的目录中查找#include"file"请求的头,然后在-iquote选项指定的目录中查找,然后在相同的位置查找使用尖括号请求的头.
此变体用于您自己的程序的头文件.预处理器按以下顺序搜索包含文件:
与包含#include语句的文件位于同一目录中.
沿着每个-iquote编译器选项指定的路径.
至于#include
此变体用于系统头文件.预处理器按以下顺序搜索包含文件:
沿着每个-I编译器选项指定的路径.
在系统目录中.
资源:
http://docs.oracle.com/cd/E19205-01/819-5265/bjadq/index.html
请注意,文本有些矛盾(请参阅示例以了解).关键短语是:" 不同之处在于,仅搜索当前目录中包含用引号括起来的名称的头文件. "
此变体用于您自己的程序的头文件.预处理器按以下顺序搜索包含文件:
当前目录(即包含"包含"文件的目录)
使用-I选项命名的目录(如果有)
系统目录(例如/ usr/include目录)
此变体用于系统头文件.预处理器按以下顺序搜索包含文件:
使用-I选项命名的目录(如果有)
系统目录(例如/ usr/include目录)
资源:
http://www.bluefern.canterbury.ac.nz/ucsc%20userdocs/forucscwebsite/c/aix/compiler.pdf
http://www-01.ibm.com/support/docview.wss?uid=swg27024204&aid=1
这两个文档的标题都是"XL C/C++编译器参考",第一个文档较旧(8.0),但更容易理解.第二个是更新的(12.1),但解密起来有点困难.
此变体用于您自己的程序的头文件.预处理器按以下顺序搜索包含文件:
当前目录(即包含"包含"文件的目录)
使用-I选项命名的目录(如果有)
系统目录(例如/ usr/vac [cpp]/include或/ usr/include目录)
此变体用于系统头文件.预处理器按以下顺序搜索包含文件:
使用-I选项命名的目录(如果有)
系统目录(例如/ usr/vac [cpp]/include或/ usr/include目录)
模式""可能会导致编译器之间出现细微的编译错误,而且由于我目前在Windows Visual C++,Linux g ++,Oracle/Solaris CC和AIX XL上工作,这是不可接受的.
无论如何,""描述的功能的优点无论如何都远非有趣,所以...
2.使用{namespace} /header.hpp模式我在工作中看到(即这不是理论,这是现实生活,痛苦的专业经验)两个具有相同名称的标题,一个在本地项目目录中,另一个在全局包含中.
由于我们使用的是""模式,并且该文件包含在本地标题和全局标题中,因此当出现奇怪错误时,无法理解实际发生的情况.
使用include中的目录可以节省我们的时间,因为用户必须要写:
#include
要么
#include
你会注意到的
#include "Header.hpp"
会成功编译,因此,仍然隐藏问题,而
#include
不会编译正常的情况.
因此,坚持使用<>符号会使开发人员强制要求使用正确的目录添加include,这是另一个更喜欢<>到""的理由.
3.结论同时使用<>表示法和命名空间表示法从预编译器中删除猜测文件的可能性,而只搜索默认的包含目录.
当然,标准库仍然照常包含在内,即:
#include#include
我通常使用<>表示系统标题,使用""表示项目标题.至于路径,只有当您想要的文件位于包含路径的子目录中时才需要.
例如,如果您需要/ usr/include/SDL /中的文件,但只有/ usr/include /在您的包含路径中,那么您可以使用:
#include
另外,请记住,除非您放置的路径以/开头,否则它与当前工作目录相关.
编辑回答:这取决于,如果只有一些库的包含,我只是在include路径中包含它的子目录,但如果库有很多标题(如几十个)那么我宁愿只有它在我指定的子目录中.一个很好的例子是Linux的系统头.你使用它们像:
#include#include
等等
编辑包含另一个好的答案:另外,如果可以想象两个或多个库提供相同名称的标题,则子目录解决方案基本上为每个标题提供命名空间.
引用C99标准(一目了然,C90标准中的措辞似乎相同,但我不能从中删除):
表单的预处理指令
# include "q-char-sequence" new-line
导致由"delimiters"之间的指定序列标识的源文件的全部内容替换该指令.以实现定义的方式搜索指定的源文件.如果不支持此搜索,或者搜索失败,该指令被重新处理,就像它读取一样
# include
new-line 使用原始指令中相同的包含序列(包括>字符,如果有的话).
因此,搜索的位置是搜索到的位置#include "whatever"
的超集#include
.目的是第一种样式将用于通常"属于"您的头,第二种方法将用于"属于"编译器/环境的头.当然,通常会有一些灰色区域 - 例如,你应该将它用于Boost标题吗?我会用#include <>
,但如果我团队中的其他人想要,我不会争论太多#include ""
.
实际上,只要构建不破坏,我认为没有人会特别注意使用哪种形式.我当然不记得曾经在代码审查中提到它(或者甚至是其他方面).