5

我习惯于在我的对象周围放置头部防护装置,例如:

#ifndef SOMETHING_H
#define SOMETHING_H

class Something {
...
}
#endif

但我得到了他们也做的代码:

#ifndef SOMETHING_H
#include "something.h"
#endif

对于每个包括。估计这样比较好。为什么?这对物体周围的警卫来说是多余的吗?

4

4 回答 4

5

它背后的想法是预处理器不需要打开头文件并读取内容来确定该头文件先前已包含,从而在编译期间节省一些时间。但是,如今大多数编译器已经足够聪明,可以发现同一文件的多个包含并忽略后续出现的内容。

于 2013-11-06T00:07:49.787 回答
5

这在此处进行了非常详细的讨论:
http ://c2.com/cgi/wiki?RedundantIncludeGuards

以下是重点:

  • 是的,这是多余的,但对于某些编译器,它可能会更快,因为如果不需要,编译器会避免打开头文件。
  • “好的编译器使这个习语变得不必要。他们注意到标头使用了包含保护习语(也就是说,文件中的所有非注释代码都用#ifndef括起来)。他们存储头文件的内部表并保护宏。在打开任何文件之前,他们会检查保护的当前值,然后跳过整个文件。”
  • “冗余的守卫有几个缺点。它们使包含部分更难阅读。它们是冗余的。它们泄露了守卫名称,这应该是标题的秘密实现细节。例如,如果有人重命名他们的守卫"
于 2013-11-06T00:12:10.387 回答
0

最好在头文件和类定义文件上有这个,这样编译时,如果循环引用了一个文件(a.cpp引用ah和b.cpp,b.cpp也引用ah,ah不会再被读取) 或其他类似情况。

最让我担心您的问题的情况是,在不同的文件中定义了相同的常量名称,并且可能会阻止编译器看到一些必要的常量、类、类型等,因为它会“相信”该文件“已被读取”。

长话短说,将不同的#ifndef 常量放在不同的文件中以防止混淆。

于 2013-11-06T00:12:04.130 回答
0

这样做的目的是节省编译时间。当编译器看到#include "something.h"时,它必须出去并获取文件。如果它这样做十次,最后九次基本上等于:

#if 0
...
#endif

那么您要付出九次查找文件并从磁盘中获取文件的成本,而没有真正的好处。(从技术上讲,编译器可以使用技巧来尝试减少或消除这种成本,但这就是它背后的想法。)

对于小型程序,节省的费用可能不是很大,这样做并没有太大的好处。对于包含数千个文件的大型程序,编译需要几个小时的情况并不少见,而这个技巧可以节省大量时间。就个人而言,在编译时间开始成为一个真正的问题之前,我不会这样做,并且像任何优化一样,我会仔细查看实际成本在哪里,然后再进行大量更改。

于 2013-11-06T00:13:21.537 回答