我正在开发一个已知只能在windows上运行并在Visual Studio下编译的代码库(它与excel紧密集成,所以它不会消失)。我想知道我是否应该使用传统的包含守卫或使用#pragma一次为我们的代码。我认为让编译器处理一次#pragma会产生更快的编译,并且在复制和粘贴时更不容易出错。它也稍微不那么丑陋;)

注意:为了获得更快的编译时间,我们可以使用冗余包含守卫,但这增加了包含文件和包含文件之间的紧密耦合。通常这是可以的,因为守卫应该基于文件名,并且只在你需要改变包含名称时才会改变。


当前回答

我回答了一个相关的问题:

#pragma once确实有一个缺点(除了不是标准的),那就是如果你在不同的位置有相同的文件(我们有这样的情况是因为我们的构建系统会四处复制文件),那么编译器会认为这些是不同的文件。

我把答案也加在这里,以防有人被这个问题绊倒,而不是其他问题。

其他回答

我只是想补充一下这个讨论,我只是在VS和GCC上编译,并且习惯使用包含守卫。我现在已经切换到#pragma一次了,对我来说唯一的原因不是性能或可移植性或标准,因为我并不关心什么是标准,只要VS和GCC支持它,那就是:

#pragma一次性减少了出现错误的可能性。

将一个头文件复制并粘贴到另一个头文件,修改它以满足自己的需要,并且忘记更改include守卫的名称,这太容易了。一旦包含了两者,就需要花费一些时间来跟踪错误,因为错误消息并不一定是清晰的。

我不认为它会对编译时间产生重大影响,但#pragma once在所有编译器中都得到了很好的支持,但实际上并不是标准的一部分。预处理器可能会快一点,因为它更容易理解你的确切意图。

#pragma一次性使用不太容易出错,需要输入的代码也更少。

为了加快编译时间,尽可能地向前声明而不是包含在.h文件中。

我更喜欢使用#pragma一次。

这篇维基百科文章介绍了两者同时使用的可能性。

我回答了一个相关的问题:

#pragma once确实有一个缺点(除了不是标准的),那就是如果你在不同的位置有相同的文件(我们有这样的情况是因为我们的构建系统会四处复制文件),那么编译器会认为这些是不同的文件。

我把答案也加在这里,以防有人被这个问题绊倒,而不是其他问题。

我通常不会使用#pragma,因为我的代码有时必须使用MSVC或GCC以外的东西进行编译(嵌入式系统的编译器并不总是有#pragma)。

所以我必须使用#include守卫。我也可以像一些回答建议的那样使用一次#pragma,但似乎没有太多的理由,而且它经常会在不支持它的编译器上引起不必要的警告。

我不确定这种务实会节省多少时间。我听说编译器通常已经识别出一个头文件中除了守卫宏之外的注释之外什么都没有,并且会在这种情况下执行#pragma。,不再处理该文件)。但我不确定这是真的还是编译器可以做这种优化。

在任何一种情况下,对我来说使用#include守卫更容易,它将在任何地方工作,而不用再担心它了。

我认为你应该做的第一件事是看看这是否真的会产生影响。您应该首先测试性能。谷歌上的一个搜索结果是这样的。

在结果页面中,对我来说,列是缓慢的,但很明显,至少到VC6,微软没有实现其他工具正在使用的包括保护优化。当include守卫是内部的时候,它花费的时间是外部守卫的50倍(外部包含守卫至少和#pragma一样好)。但让我们考虑一下这可能产生的影响:

根据给出的表格,打开include并检查它的时间是使用#pragma的等效时间的50倍。但在1999年,每个文件的实际时间是1微秒!

那么,一个TU会有多少重复的头?这取决于你的风格,但如果我们说平均每个TU有100个副本,那么在1999年,我们可能要为每个TU支付100微秒。随着HDD的改进,现在这个数字可能会显著降低,但即使是这样,通过预编译头文件和正确的依赖关系,跟踪一个项目的累计成本几乎肯定是你构建时间中微不足道的一部分。

现在,在另一方面,可能不太可能,如果你曾经移动到一个不支持#pragma的编译器,那么考虑一下要花多少时间来更新你的整个源代码库,以包含守卫而不是#pragma?

微软没有理由不能像GCC和其他编译器一样实现包含保护优化(实际上有人能确认他们的最新版本是否实现了这一点吗?)恕我直言,#pragma once除了限制你对可选编译器的选择外,几乎没有什么作用。