使用double包括C ++中的守卫

时间:2017-06-19 11:17:03

标签: c++ macros linker

所以我最近讨论了我的工作,其中我质疑使用包含一个后卫的守卫。 双重保护的含义如下:

标题文件," header_a.hpp":

#ifndef __HEADER_A_HPP__
#define __HEADER_A_HPP__
...
...
#endif

将头文件包含在头文件或源文件中的任何位置时:

#ifndef __HEADER_A_HPP__
#include "header_a.hpp"
#endif

现在我明白在头文件中使用guard是为了防止多次包含已经定义的头文件,这是常见的并且记录良好。如果已经定义了宏,则整个头文件被视为“空白”'由编译器和双包含被阻止。很简单。

我不明白的问题是在#ifndef __HEADER_A_HPP__周围使用#endif#include "header_a.hpp"。同事告诉我,这为夹杂物增加了第二层保护,但是如果第一层绝对完成这项工作(或者是吗?),我就不知道第二层是如何有用的。

我能想到的唯一好处是它可以直接阻止链接器找到文件。这是否意味着改善编译时间(这没有被提及作为一个好处),或者在这里有什么其他工作我没有看到?

5 个答案:

答案 0 :(得分:104)

我很确定添加另一个包含守卫是一个不好的做法,如:

#ifndef __HEADER_A_HPP__
#include "header_a.hpp"
#endif

以下是一些原因:

  1. 为了避免双重包含,只需在头文件本身中添加一个通常的include guard即可。它做得很好。另一个包括代替地方的警卫只会混淆代码并降低可读性。

  2. 它增加了不必要的依赖关系。如果您在头文件中更改了include guard,则必须在包含标题的所有位置更改它。

  3. 绝对不是比较整个编译/链接过程最昂贵的操作,因此很难减少总构建时间。

  4. 任何有价值的编译器already optimizes file-wide include-guards

答案 1 :(得分:49)

标题文件中添加包含警戒的原因是为了防止标题的内容多次被拉入翻译单元。这是正常的,历史悠久的做法。

文件中放置冗余包含警卫的原因是为了避免打开包含的头文件,并且在过去可能会显着加快编译的速度。这些天,打开文件比以前快得多;此外,编译器非常聪明地记住他们已经看过哪些文件,并且他们理解包含守护成语,因此他们可以自己弄清楚他们不需要再次打开文件。这有点挥手,但最重要的是,不再需要这个额外的层。

编辑:这里的另一个因素是编译C ++ 比编译C更复杂,因此它需要更长的,使打开包含文件的时间变得更小,编译翻译单元所花费的时间不那么重要。

答案 2 :(得分:22)

  

我能想到的唯一好处是它可以直接阻止链接器找到文件。

链接器不会受到任何影响。

它可以防止预处理器打扰找到文件,但是如果定义了防护,那意味着它已经找到了该文件。我怀疑如果预处理时间完全减少,效果将是非常小的,除了在病理上最复杂的包括怪物。

它有一个缺点,如果防护装置发生变化(例如由于与另一个防护装置发生冲突),必须更改包含指令之前的所有条件,以使它们起作用。如果其他东西使用了前一个后卫,则必须更改条件,以使include指令本身正常工作。

P.S。 __HEADER_A_HPP__是为实现保留的符号,因此不是您可以定义的符号。为警卫使用另一个名字。

答案 3 :(得分:17)

更传统的(大型机)平台上的旧编译器(我们在这里谈到2000年代中期)并不习惯在其他答案中描述优化,因此它确实用于显着减慢预处理时间重新读取已经包含的头文件(请记住,在一个庞大的,整体的企业项目中,你将包括很多头文件)。作为一个例子,我已经看到数据表明一个文件有26倍的加速,文件包含256个头文件,每个文件包含VisualAge C ++ 6 for AIX编译器(可追溯到2000年代中期)的相同256个头文件。这是一个相当极端的例子,但这种加速确实加起来。

然而,所有现代编译器,即使在AIX和Solaris等大型机平台上,都对头部包含进行了足够的优化,这些日子的差异确实可以忽略不计。因此没有充分的理由再拥有这些。

然而,这确实解释了为什么有些公司仍然坚持这种做法,因为相对最近(至少在C / C ++代码库年龄方面),对于非常大的单片项目来说仍然是值得的。

答案 4 :(得分:8)

虽然有人反对它,但在实践中#pragma once'完美的工作,主编译器(gcc / g ++,vc ++)支持它。

因此,无论人们传播什么样的纯粹论证,它的效果都会好很多:

  1. 快速
  2. 没有维护,因为你复制了一面旧旗子而没有神秘的不包含的麻烦
  3. 与文字
  4. 中传播的神秘线条有明显含义的单行

    所以简单地说:

    #pragma once
    

    在文件的开头,那就是它。优化,可维护,随时可用。