为啥在包含警卫之前放置#include

     2023-02-22     151

关键词:

【中文标题】为啥在包含警卫之前放置#include【英文标题】:Why Placing #include BEFORE include guards为什么在包含警卫之前放置#include 【发布时间】:2014-05-19 10:37:05 【问题描述】:

在头文件中的包含保护之前放置#include指令是否有任何正当理由:

#include "jsarray.h"
#include "jsanalyze.h"
#include "jscompartment.h"
#include "jsgcmark.h"
#include "jsinfer.h"
#include "jsprf.h"
#include "vm/GlobalObject.h"

#include "vm/Stack-inl.h"

#ifndef jsinferinlines_h___
#define jsinferinlines_h___

//main body mostly inline functions 

#endif

注意,这个例子取自一个真实的高调开源项目,应该由经验丰富的程序员开发——Firefox 10 中使用的 Mozilla Spidermonkey 开源 Javascript 引擎(最新版本中也存在相同的头文件) .

在备受瞩目的项目中,我认为他们的设计背后一定有一些正当的理由。在包含防护之前有 #include 的正当理由是什么?它是适用于仅内联函数头文件的模式吗?还要注意,这个头文件(jsinferinlines.h)实际上是通过最后一个#include "vm/Stack-inl.h"(这个头文件包括很多其他头文件,其中一个实际上又包括这个jsinferinlines.h)指令在include保护之前包含了自己,这个对我来说更没有意义。

【问题讨论】:

【参考方案1】:

因为您希望这些标头包含它们自己的保护,因此它并没有什么区别。

还要注意,这个头文件(jsinferinlines.h)实际上是通过最后一个#include“vm/Stack-inl.h”包含自己的(这个头文件包括很多其他头文件,其中一个实际上包括这个jsinferinlines .h 再次)在包含保护之前的指令,这对我来说更没有意义。

不会有任何不同,因为包含该文件时的工作流程将是:

包括所有标题到"vm/Stack-inl.h" 包括"vm/Stack-inl.h" 直到最后一个#include "jsinferinlines.h"(您的文件) 再次包含文件jsinferinlines.h(跳过所有以前的包含,因为包含保护) 过去#include "vm/Stack-inl.h" 终于从#ifndef jsinferinlines_h___开始处理

但总的来说,相互头递归是不好的,应该不惜一切代价避免。

【讨论】:

它对编译性能有相当大的影响,因为它必须先打开所有这些文件。 (当然,真正的编译器通常会缓存它们,但仍然如此。) 如果我们有两个包含彼此的文件怎么办? (我不是在这里讨论这种做法有多糟糕)。在包含守卫的正常使用中,当它们是文件中的第一件事时,什么都不会发生。如果包含在守卫之前,编译器将进入无限循环。 @WojtekSurowka,当然。不过,这是你的错误。 @Jeffrey - 如果文件包含自身,现代编译器会做什么? @WojtekSurowka:现代编译器将检测常见的“包含守卫”模式并相应地优化对fopen 的调用。包含的合法使用应该像优化没有发生一样工作(否则它是一个错误),并且应该检测到错误(无限循环等......)(否则它是一个错误)。当然,现代版本的 gcc 和 clang 应该可以很好地处理这些边缘情况。【参考方案2】:

当时 SpiderMonkey 标头中有很多包含循环,将标头保护置于顶部会导致难以理解的编译错误 - 我怀疑将标头保护置于包含之下只是清理包含的增量步骤。

不过,我无法告诉您导致它产生影响的确切包含顺序。

如今,SM 标头中不应该有任何包含循环,并且它们的样式是通过 Nicholas Nethercote 编写的 python 脚本强制执行的。如果您今天查看 jsinferinlines.h,您会看到标头保护位于其所属的顶部。

【讨论】:

包括问题和包括警卫

...描述】:我和我的团队正在开展一个相当大的项目,其中包含许多具有各自头文件和源文件的类。我们正在尝试将C++库和项目类头文件中的所有包含合并到一个名为“Includes.h”的文件中,该文件包含在每个头文件中。这样做时... 查看详情

C包括警卫[重复]

...发布时间】:2011-11-2511:48:52【问题描述】:当file1.c首次包含inc.h(包含包含保护#ifndefINC_H)时,将执行#defineINC_H。但是现在,当另一个file2.c包含相同的inc.h时,宏INC_H是否已经定义,都是同一个故事,之前的定义不在这里传播?... 查看详情

为啥在实现类的方法名称之前会包含接口引用? [复制]

】为啥在实现类的方法名称之前会包含接口引用?[复制]【英文标题】:anyreasonwhyaninterfacereferencewouldbeincludedbeforeamethodnameonanimplementingclass?[duplicate]为什么在实现类的方法名称之前会包含接口引用?[复制]【发布时间】:2017-05-1500:... 查看详情

包括声明之外包括警卫

】包括声明之外包括警卫【英文标题】:Includestatementsoutsideincludeguards【发布时间】:2015-04-2920:43:26【问题描述】:我最近开始在一个项目中遇到这个问题:#include<string.h>//includesbeforeincludeguards#include"whatever.h"#ifndefCLASSNAME_H//he... 查看详情

c ++模板并包含警卫[重复]

】c++模板并包含警卫[重复]【英文标题】:c++templateandincludeguards[duplicate]【发布时间】:2014-10-0101:12:54【问题描述】:我对C++比较陌生,所以我的问题可能有一个简单的答案;但是,我不知道为什么我的代码在我认为应该工作的... 查看详情

Erlang,使用警卫之前的语法错误

】Erlang,使用警卫之前的语法错误【英文标题】:Erlang,Syntaxerrorbeforeusingaguard【发布时间】:2015-02-2415:37:25【问题描述】:map_search_pred(Map,Pred)whereis_map(Map)->map_search_pred(maps:to_list(Map),Pred);map_search_pred([H|Tail],Pred)->casePr 查看详情

Angular2 相对路径在警卫中导航

】Angular2相对路径在警卫中导航【英文标题】:Angular2relativeroutenavigateinaguard【发布时间】:2017-04-2102:28:02【问题描述】:我们在此处提供了子路由定义,其中我们使用保护来检查用户在使用我们的服务之前是否已接受条款。accoun... 查看详情

为啥openmp不根据手动NUMA绑定放置线程?

】为啥openmp不根据手动NUMA绑定放置线程?【英文标题】:Whydoesn\'topenmpplacethreadsbasedonmanualNUMAbind?为什么openmp不根据手动NUMA绑定放置线程?【发布时间】:2018-03-0714:22:37【问题描述】:我正在构建一个可识别numa的处理器,该处理... 查看详情

Vigenere Cipher 只能在处理 C 中的空格(“”)之前有效 - 为啥?

】VigenereCipher只能在处理C中的空格(“”)之前有效-为啥?【英文标题】:VigenereCipheronlyworksupuntildealingwithaspace("")inC-why?VigenereCipher只能在处理C中的空格(“”)之前有效-为什么?【发布时间】:2016-01-2021:00:23【问题描... 查看详情

用于包括警卫的名称?

...【发布时间】:2018-05-1517:15:49【问题描述】:在为他们的包含保护选择名称时,人们倾向于遵循哪些准则?我不明白为什么.h文件的名称会与包含保护中使用的名称略有不同。例如,我见过sphere.h,然后是#ifndefSPHERE_H_。我可以轻... 查看详情

[pa2014]muzeum(代码片段)

[PA2014]Muzeum题目大意:有(n)件展品和(m)个警卫,每件展品有一个坐标((x_i,y_i))和价值(v_i),每个警卫的坐标为((x_i,y_i))。每个警卫面朝(y)轴负方向,左右视角都为( heta),警卫视线范围内的展品不能偷。你可以收买一些警卫,使其放... 查看详情

为啥要将 <title>-tag 放置到 <head> 元素中?

】为啥要将<title>-tag放置到<head>元素中?【英文标题】:Whyhasthe<title>-tagtobeplacedintothe<head>element?为什么要将<title>-tag放置到<head>元素中?【发布时间】:2016-08-2920:35:09【问题描述】:在具体示例中,我... 查看详情

为啥我的程序在实际应该执行之前执行?

】为啥我的程序在实际应该执行之前执行?【英文标题】:Whymyprogramexecutesbeforewhenitactuallysupposedto?为什么我的程序在实际应该执行之前执行?【发布时间】:2020-04-2819:48:55【问题描述】:好的,我已经写了一个代码,这个程序一... 查看详情

为啥要在项目中使用#include_next?

】为啥要在项目中使用#include_next?【英文标题】:Whywouldoneuse#include_nextinaproject?为什么要在项目中使用#include_next?【发布时间】:2012-05-0222:24:16【问题描述】:引用iOSDocumentationonWrapperHeaders:#include_next不区分和"file"包含,也不... 查看详情

为啥尝试在 GoogleMap 上放置标记时出现 NullPointerException?

】为啥尝试在GoogleMap上放置标记时出现NullPointerException?【英文标题】:WhyamIgettingaNullPointerExceptionWhenAttemptingToPlaceaMarkeronGoogleMap?为什么尝试在GoogleMap上放置标记时出现NullPointerException?【发布时间】:2021-11-3003:49:22【问题描述】... 查看详情

为啥 Scala 在类名的末尾放置一个美元符号?

】为啥Scala在类名的末尾放置一个美元符号?【英文标题】:WhydoesScalaplaceadollarsignattheendofclassnames?为什么Scala在类名的末尾放置一个美元符号?【发布时间】:2022-01-2212:19:46【问题描述】:在Scala中,当您查询对象的类或类名时... 查看详情

为啥 Scala 在类名的末尾放置一个美元符号?

】为啥Scala在类名的末尾放置一个美元符号?【英文标题】:WhydoesScalaplaceadollarsignattheendofclassnames?为什么Scala在类名的末尾放置一个美元符号?【发布时间】:2017-05-2500:29:23【问题描述】:在Scala中,当您查询对象的类或类名时... 查看详情

犯错误:多个定义...尽管包括警卫

...定.c文件中的所有函数)的非常奇怪的错误。我正在使用包含保护来防止多个声明我的头文件不包含任何定义,只有声明。文件中没有定义变量,只有函数。我仔细检查了:只有.h 查看详情