C++ #include 语义

2024-04-12

这是同一预处理指令的多个问题。

1 - 或“”?

除了 MSDN 中找到的信息之外:

#include 指令 (C-C++) https://msdn.microsoft.com/en-us/library/36k2cdd4.aspx

1.a:这两种表示法有什么区别?
1.b:所有编译器都以相同的方式实现它们吗?
1.c:什么时候使用,什么时候使用“”(即,使用一个或另一个作为标题包含的标准是什么)?

2 - #include {The Project/The Header.hpp} 或 {The Leader.hpp} ?

我至少见过两种编写项目标题的方法。 考虑到您至少有 4 种类型的标头,即:

  • 您的项目的私有标头?
  • 项目的标头,但正在导出符号(因此是“公共”)
  • 您的模块链接的另一个项目的标头
  • 编译器或标准库的头文件

对于每种类型的标头:

2.a:你会使用 还是 "" ?
2.b:您会包含在 {The Project/The Header.hpp} 中,还是仅包含在 {The Header.hpp} 中?

3 - 奖金

3.a:您是否在树状组织中使用源和/或标头(即目录中的目录,而不是“一个目录中的每个文件”)来处理项目,优点/缺点是什么?


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

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

#include <namespace/header.hpp>

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

当然,这意味着项目头所在的项目目录也应该作为“默认包含头”添加到 makefile 中。

之所以做出这样的选择,是因为我查到了以下信息:

1. include "" 模式依赖于编译器

下面我将给出答案

1.a 标准

Source:

  • C++14 工作草案 n3797:https://isocpp.org/files/papers/N3797.pdf https://isocpp.org/files/papers/N3797.pdf
  • C++11、C++98、C99、C89(所有这些标准中引用的部分均未更改)

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

表单的预处理指令

  #include <h-char-sequence> new-line

在一系列实现定义的位置中搜索由 分隔符之间的指定序列唯一标识的标头,并导致用标头的整个内容替换该指令。如何指定位置或标识标头是实现定义的。

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

然后,下一段:

表单的预处理指令

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

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

  #include <h-char-sequence> new-line

具有与原始指令相同的包含序列(包括 > 字符,如果有的话)。

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

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

请注意,由于某种原因,标准中没有任何地方对“系统”或“库”标头或其他标头之间存在差异。唯一的区别似乎是 #include <...> 似乎以标头为目标,而 #include "..." 似乎以源为目标(至少在英文措辞中)。

1.b 视觉C++:

Source:

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

#include“MyFile.hpp”

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

  1. 与包含 #include 语句的文件位于同一目录中。
  2. 在任何先前打开的目录中,包含文件的顺序与打开文件的顺序相反。搜索从最后打开的包含文件的目录开始,一直到最先打开的包含文件的目录。
  3. 沿着每个 /I 编译器选项指定的路径。
  4. (*) 沿着 INCLUDE 环境变量或开发环境默认包含指定的路径。

#include

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

  1. 沿着每个 /I 编译器选项指定的路径。
  2. (*) 沿着 INCLUDE 环境变量或开发环境默认包含指定的路径。

注意最后一步

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

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

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

1.c g++

Source:

  • https://gcc.gnu.org/onlinedocs/cpp/Header-Files.html 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-Syntax.html
  • https://gcc.gnu.org/onlinedocs/cpp/Include-Operation.html https://gcc.gnu.org/onlinedocs/cpp/Include-Operation.html
  • https://gcc.gnu.org/onlinedocs/cpp/Initation.html https://gcc.gnu.org/onlinedocs/cpp/Invocation.html
  • https://gcc.gnu.org/onlinedocs/cpp/Search-Path.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/Once-Only-Headers.html
  • https://gcc.gnu.org/onlinedocs/cpp/Wrapper-Headers.html https://gcc.gnu.org/onlinedocs/cpp/Wrapper-Headers.html
  • https://gcc.gnu.org/onlinedocs/cpp/System-Headers.html https://gcc.gnu.org/onlinedocs/cpp/System-Headers.html

以下引用总结了该过程:

GCC [...] 将查找使用 #include 请求的标头<file>在 [系统目录] [...] 在默认目录之前按从左到右的顺序搜索所有由 -I 命名的目录

GCC 首先在包含当前文件的目录中查找使用 #include "file" 请求的标头,然后在 -iquote 选项指定的目录中查找,然后在相同的位置查找使用尖括号请求的标头。

#include“MyFile.hpp”

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

  1. 与包含 #include 语句的文件位于同一目录中。
  2. 沿着每个 -iquote 编译器选项指定的路径。
  3. 至于#include<MyFile.hpp>

#include

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

  1. 沿着每个 -I 编译器选项指定的路径。
  2. 在系统目录内。

1.d Oracle/Sun Studio CC

Source:

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

请注意,文本有些自相矛盾(请参阅示例以理解)。关键短语是:“区别在于,仅搜索当前目录中名称已用引号引起来的头文件。

#include“MyFile.hpp”

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

  1. 当前目录(即包含“include”文件的目录)
  2. 使用 -I 选项命名的目录(如果有)
  3. 系统目录(例如/usr/include目录)

#include

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

  1. 使用 -I 选项命名的目录(如果有)
  2. 系统目录(例如/usr/include目录)

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

Source:

  • http://www.bluefern.canterbury.ac.nz/ucsc%20userdocs/forucscwebsite/c/aix/compiler.pdf http://www.bluefern.canterbury.ac.nz/ucsc%20userdocs/forucscwebsite/c/aix/compiler.pdf

两个文档的标题都是“XL C/C++ 编译器参考” 第一个文档较旧 (8.0),但更容易理解。第二个是较新的(12.1),但解密有点困难。

#include“MyFile.hpp”

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

  1. 当前目录(即包含“include”文件的目录)
  2. 使用 -I 选项命名的目录(如果有)
  3. 系统目录(例如 /usr/vac[cpp]/include 或 /usr/include 目录)

#include

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

  1. 使用 -I 选项命名的目录(如果有)
  2. 系统目录(例如 /usr/vac[cpp]/include 或 /usr/include 目录)

1.e 结论

模式“”可能会导致跨编译器出现微妙的编译错误,并且由于我目前在 Windows Visual C++、Linux g++、Oracle/Solaris CC 和 AIX XL 上工作,这是不可接受的。

无论如何,“”所描述的功能的优点无论如何都谈不上有趣,所以......

2.使用{namespace}/header.hpp模式

我在工作中看到(即这不是理论,这是现实生活中,痛苦的专业经历)两个同名的标头,一个在本地项目目录中,另一个在全局包含中。

由于我们使用的是“”模式,并且该文件同时包含在本地标头和全局标头中,因此当出现奇怪的错误时,无法了解到底发生了什么。

使用包含中的目录可以节省我们的时间,因为用户必须编写:

#include <MyLocalProject/Header.hpp>

or

#include <GlobalInclude/Header.hpp>

你会注意到,虽然

#include "Header.hpp"

会成功编译,因此仍然隐藏问题,而

#include <Header.hpp>

在正常情况下不会编译。

因此,坚持使用 表示法将强制开发人员在包含文件前加上正确的目录前缀,这是更喜欢 而不是 "" 的另一个原因。

三、结论

同时使用 表示法和命名空间表示法可以消除预编译器猜测文件的可能性,而不是仅搜索默认包含目录。

当然,标准库还是照常包含在内,即:

#include <cstdlib>
#include <vector>
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

C++ #include 语义 的相关文章

随机推荐

  • 嵌套表格中的长字换行

    我正在尝试总结一个很长的词 我看过这个帖子 如何防止长单词破坏我的 div https stackoverflow com questions 320184 how to prevent long words from breaking m
  • 生成谷歌地图图像[关闭]

    很难说出这里问的是什么 这个问题是含糊的 模糊的 不完整的 过于宽泛的或修辞性的 无法以目前的形式得到合理的回答 如需帮助澄清此问题以便重新打开 访问帮助中心 help reopen questions 我想允许我的网站的最终用户生成谷歌地
  • 如何使用Logback以JSON方式登录?

    我是 SLF4J 和 Logback 的新手 我正在尝试记录以下 API 的每个请求和响应link https pivotal io de application transformation recipes observability r
  • 内容可编辑和非按钮元素

    如果使用按钮 我可以轻松地对内容可编辑的选择执行 execcommand 但是使用任何其他元素都会失败 http jsbin com atike edit http jsbin com atike edit 为什么会这样以及如何使用 div
  • 具有通用向量和对类型的对向量,模板的模板

    我想将一个成对的向量传递给一个函数 实际的向量实现以及对的类型应该是模板参数 我想到了这样的事情 template
  • jquery - firefox 中的 event.preventDefault()

    我有问题event preventDefault 在 Firefox 中 它不起作用 这是 jquery 代码 facebook del 1 click function event preventDefault var selector
  • MVC(模型-视图-控制器)——能用简单的术语解释一下吗? [关闭]

    Closed 这个问题是无关 help closed questions 目前不接受答案 我需要向一位不太懂技术的经理解释 MVC 模型 视图 控制器 概念 但遇到了麻烦 问题是解释需要处于 你的奶奶会明白的 水平 例如即使是相当简单的解释
  • 如何快速发送自动短信? [关闭]

    Closed 这个问题需要多问focused help closed questions 目前不接受答案 我想在我的应用程序中自动发送短信 我怎样才能快速做到这一点 我使用 MFMessageComposeViewController 发送
  • 对 Map 列表进行排序

    我有一个像这样创建的列表变量 List
  • 观察者 - 显式指定感兴趣的修改 - JAVA 实现

    I asked here https stackoverflow com questions 65198966 observer pattern observe attributes independently当我需要通知时我应该如何处理这
  • 为什么“System.out.println”在 Android 中不起作用?

    我想在控制台中打印一些内容 以便我可以调试它 但由于某种原因 我的 Android 应用程序中没有打印任何内容 那我该如何调试呢 public class HelloWebview extends Activity WebView webv
  • Angular 2 引导选项 - AOT 与 JIT

    刚开始使用 Angular 2 Angular 2 中的各种 Bootstrapping 选项有哪些 为什么当我进行更改并刷新时 index html 只需要很少的时间来检索 HTML 标记 它们之间的区别 有两种选择 动态引导 使用的编译
  • 如何为 Debian/Ubuntu 打包 Mono 应用程序

    是否有任何用于为 Debian Ubuntu 打包 Mono 应用程序的指南或工具 比如将应用程序附带的程序集放在哪里等 Mono 有一些关于打包的一般准则 但这些准则并非特定于 Debian Ubuntu 它们的做法可能有所不同 http
  • C:将x86指令放入数组并执行它们[重复]

    这个问题在这里已经有答案了 有没有办法将处理器指令放入数组中 使其内存段可执行并将其作为简单函数运行 int main char myarr 13 0x90 0xc3 void myfunc void myarr myfunc return
  • Google Calendar API - 通过服务帐户访问自己的日历

    我想访问 Google Calendar API 以使用 Python 插入条目 我创建了一个服务帐号在Google API控制台上 添加私钥 下载它 但是 当我尝试修改同一帐户上的任何日历时 我收到以下错误消息 读书作品 Code is
  • scala 框架中支持 PostgreSQL 特定的 array_agg 函数吗?

    是否有一些 scala 关系数据库框架 anorm squeryl 等 使用类似 postgres 的聚合器在分组后生成列表 或者至少模拟其使用 我期望有两个层次的实施 一个 标准 的 其中至少任何带有 array agg 的 SQL 分组
  • 我的 Rails 应用程序的捆绑包安装冻结

    有时 在使用 Rails 应用程序时 运行bundle install命令在处理 Rails Gemfile 时冻结 我尝试过清除缓存 但没有任何改善 请务必仔细检查并确保您声明的是 Rails 版本 如果不声明版本 Bundler 最终可
  • 将值传递给 Android 中的自定义视图

    Cheers 我有一个接收用户输入 2 个数字 宽度和高度 的应用程序 理论上根据该输入 我有一个应该绘制网格 宽度和高度 的自定义视图 Note 应在视图尝试绘制自身之前接收这两个值 这两个值不是恒定的 因此我认为 XML 方法没有帮助
  • 在 R 中使用 igraph 获取连接组件

    我想找到一张图的所有连接组件 其中组件具有多个元素 使用clusters给出不同集群的成员资格并使用cliques不给出连通分量 这是后续 R中列表的多重交集 https stackoverflow com questions 304065
  • C++ #include 语义

    这是同一预处理指令的多个问题 1 或 除了 MSDN 中找到的信息之外 include 指令 C C https msdn microsoft com en us library 36k2cdd4 aspx 1 a 这两种表示法有什么区别