当前位置:  开发笔记 > 编程语言 > 正文

C++ #include语义

如何解决《C++#include语义》经验,为你挑选了3个好方法。

对于相同的预处理指令,这是一个多重问题.

1 - <>或""?

除了在MSDN中找到的信息:

#include指令(C-C++)

1.a:两种符号之间有什么区别?
1.b:所有编译器都以同样的方式实现它们吗?
1.c:你什么时候使用<>,什么时候会使用""(即你用什么标准来使用一个或另一个标题包括在内)?

2 - #include {TheProject/TheHeader.hpp}或{TheHeader.hpp}?

我已经看到至少有两种写作方式包括一个项目标题.考虑到您至少有4种类型的标题,即:

您项目的私有标题?

您的项目的标题,但导出符号(因此,"公共")

模块链接的另一个项目的标题

编译器或标准库的标头

对于每种标题:

2.a:你会用<>或""吗?
2.b:您是否只使用{TheProject/TheHeader.hpp}或{TheHeader.hpp}?

3 - 奖金

3.a:你是否在一个类似树的组织中使用源和/或标题的项目(即目录中的目录,而不是"一个目录中的每个文件"),有什么优点/缺点?



1> paercebal..:

在阅读完所有答案以及编译器文档后,我决定遵循以下标准.

对于所有文件,无论是项目标题还是外部标题,始终使用模式:

#include 

命名空间至少是一个目录深,以避免冲突.

当然,这意味着项目标题所在的项目目录也应该作为"default include header"添加到makefile中.

这个选择的原因是我找到了以下信息:

1.包含""模式依赖于编译器

我将在下面给出答案

1.a标准

资源:

C++ 14 Working Draft n3797:https://isocpp.org/files/papers/N3797.pdf

C++ 11,C++ 98,C99,C89(引用的部分在所有这些标准中保持不变)

在16.2源文件包含部分中,我们可以读到:

表单的预处理指令

  #include  new-line

搜索一系列实现定义的位置,以查找由<和>分隔符之间的指定序列唯一标识的标头,并使标头的整个内容替换该指令.如何指定场所或标识的头是实现定义的.

这意味着#include <...>将以实现定义的方式搜索文件.

然后,下一段:

表单的预处理指令

  #include "q-char-sequence" new-line

导致由"delimiters"之间的指定序列标识的源文件的全部内容替换该指令.以实现定义的方式搜索指定的源文件.如果不支持此搜索,或者搜索失败,该指令被重新处理,就像它读取一样

  #include  new-line

使用原始指令中相同的包含序列(包括>字符,如果有的话).

这意味着#include"..."将以实现定义的方式搜索文件,然后,如果找不到该文件,将执行另一次搜索,就好像它是#include <...>

结论是我们必须阅读编译器文档.

请注意,由于某些原因,标准中没有任何地方在"系统"或"库"标题或其他标题之间进行区分.唯一的区别似乎#include <...>似乎是目标标题,而#include"..."似乎是目标来源(至少在英语措辞中).

1.b Visual C++:

资源:

http://msdn.microsoft.com/en-us/library/36k2cdd4.aspx

#include"MyFile.hpp"

预处理器按以下顺序搜索包含文件:

    与包含#include语句的文件位于同一目录中.

    在任何先前打开的包含文件的目录中,按照打开它们的相反顺序.搜索从最后打开的包含文件的目录开始,并继续通过首先打开的包含文件的目录.

    沿着每个/ I编译器选项指定的路径.

    (*)沿INCLUDE环境变量指定的路径或开发环境默认包含.

#include

预处理器按以下顺序搜索包含文件:

    沿着每个/ I编译器选项指定的路径.

    (*)沿INCLUDE环境变量指定的路径或开发环境默认包含.

关于最后一步的注意事项

该文档不清楚"沿着INCLUDE环境变量指定的路径"部分<...> ,"..."包括.以下引用使其符合标准:

对于指定为#include"path-spec"的包含文件,目录搜索从父文件的目录开始,然后遍历任何祖父文件的目录.也就是说,搜索从包含源文件的目录开始,该源文件包含正在处理的#include指令.如果没有祖父文件并且找不到该文件,则继续搜索,就好像文件名用尖括号括起来一样.

因此,最后一步(用星号标记)是阅读整个文件的解释.

1.c g ++

资源:

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"MyFile.hpp"

此变体用于您自己的程序的头文件.预处理器按以下顺序搜索包含文件:

    与包含#include语句的文件位于同一目录中.

    沿着每个-iquote编译器选项指定的路径.

    至于#include

#include

此变体用于系统头文件.预处理器按以下顺序搜索包含文件:

    沿着每个-I编译器选项指定的路径.

    在系统目录中.

1.d Oracle/Sun Studio CC

资源:

http://docs.oracle.com/cd/E19205-01/819-5265/bjadq/index.html

请注意,文本有些矛盾(请参阅示例以了解).关键短语是:" 不同之处在于,仅搜索当前目录中包含用引号括起来的名称的头文件. "

#include"MyFile.hpp"

此变体用于您自己的程序的头文件.预处理器按以下顺序搜索包含文件:

    当前目录(即包含"包含"文件的目录)

    使用-I选项命名的目录(如果有)

    系统目录(例如/ usr/include目录)

#include

此变体用于系统头文件.预处理器按以下顺序搜索包含文件:

    使用-I选项命名的目录(如果有)

    系统目录(例如/ usr/include目录)

1.e XL C/C++编译器参考 - IBM/AIX

资源:

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),但解密起来有点困难.

#include"MyFile.hpp"

此变体用于您自己的程序的头文件.预处理器按以下顺序搜索包含文件:

    当前目录(即包含"包含"文件的目录)

    使用-I选项命名的目录(如果有)

    系统目录(例如/ usr/vac [cpp]/include或/ usr/include目录)

#include

此变体用于系统头文件.预处理器按以下顺序搜索包含文件:

    使用-I选项命名的目录(如果有)

    系统目录(例如/ usr/vac [cpp]/include或/ usr/include目录)

1.e结论

模式""可能会导致编译器之间出现细微的编译错误,而且由于我目前在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 


"
)两个具有相同名称的标题,一个在本地项目目录中,另一个在全局包含中.

2> Evan Teran..:

我通常使用<>表示系统标题,使用""表示项目标题.至于路径,只有当您想要的文件位于包含路径的子目录中时才需要.

例如,如果您需要/ usr/include/SDL /中的文件,但只有/ usr/include /在您的包含路径中,那么您可以使用:

#include 

另外,请记住,除非您放置的路径以/开头,否则它与当前工作目录相关.

编辑回答:这取决于,如果只有一些库的包含,我只是在include路径中包含它的子目录,但如果库有很多标题(如几十个)那么我宁愿只有它在我指定的子目录中.一个很好的例子是Linux的系统头.你使用它们像:

#include 
#include 

等等

编辑包含另一个好的答案:另外,如果可以想象两个或多个库提供相同名称的标题,则子目录解决方案基本上为每个标题提供命名空间.



3> Michael Burr..:

引用C99标准(一目了然,C90标准中的措辞似乎相同,但我不能从中删除):

表单的预处理指令

# include "q-char-sequence" new-line

导致由"delimiters"之间的指定序列标识的源文件的全部内容替换该指令.以实现定义的方式搜索指定的源文件.如果不支持此搜索,或者搜索失败,该指令被重新处理,就像它读取一样

# include new-line

使用原始指令中相同的包含序列(包括>字符,如果有的话).

因此,搜索的位置是搜索到的位置#include "whatever"的超集#include .目的是第一种样式将用于通常"属于"您的头,第二种方法将用于"属于"编译器/环境的头.当然,通常会有一些灰色区域 - 例如,你应该将它用于Boost标题吗?我会用#include <>,但如果我团队中的其他人想要,我不会争论太多#include "".

实际上,只要构建不破坏,我认为没有人会特别注意使用哪种形式.我当然不记得曾经在代码审查中提到它(或者甚至是其他方面).

推荐阅读
家具销售_903
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有