我正在开发一个已知只能在windows上运行并在Visual Studio下编译的代码库(它与excel紧密集成,所以它不会消失)。我想知道我是否应该使用传统的包含守卫或使用#pragma一次为我们的代码。我认为让编译器处理一次#pragma会产生更快的编译,并且在复制和粘贴时更不容易出错。它也稍微不那么丑陋;)
注意:为了获得更快的编译时间,我们可以使用冗余包含守卫,但这增加了包含文件和包含文件之间的紧密耦合。通常这是可以的,因为守卫应该基于文件名,并且只在你需要改变包含名称时才会改变。
我正在开发一个已知只能在windows上运行并在Visual Studio下编译的代码库(它与excel紧密集成,所以它不会消失)。我想知道我是否应该使用传统的包含守卫或使用#pragma一次为我们的代码。我认为让编译器处理一次#pragma会产生更快的编译,并且在复制和粘贴时更不容易出错。它也稍微不那么丑陋;)
注意:为了获得更快的编译时间,我们可以使用冗余包含守卫,但这增加了包含文件和包含文件之间的紧密耦合。通常这是可以的,因为守卫应该基于文件名,并且只在你需要改变包含名称时才会改变。
当前回答
直到#pragma成为标准的那一天(这不是未来标准的优先级),我建议你使用它并使用守卫,这样:
#ifndef BLAH_H
#define BLAH_H
#pragma once
// ...
#endif
原因如下:
#pragma once is not standard, so it is possible that some compiler don't provide the functionality. That said, all major compiler supports it. If a compiler don't know it, at least it will be ignored. As there is no standard behavior for #pragma once, you shouldn't assume that the behavior will be the same on all compiler. The guards will ensure at least that the basic assumption is the same for all compilers that at least implement the needed preprocessor instructions for guards. On most compilers, #pragma once will speed up compilation (of one cpp) because the compiler will not reopen the file containing this instruction. So having it in a file might help, or not, depending on the compiler. I heard g++ can do the same optimization when guards are detected but it have to be confirmed.
同时使用这两种编译器,可以充分利用每种编译器的优点。
现在,如果您没有一些自动脚本来生成守卫,那么只使用#pragma一次可能会更方便。要知道这对可移植代码意味着什么。(我使用VAssistX生成守卫和pragma一次快速)
你应该总是认为你的代码是可移植的(因为你不知道未来是由什么组成的),但如果你真的认为它不应该用另一个编译器编译(例如非常特定的嵌入式硬件的代码),那么你应该检查一下编译器文档中关于#pragma的内容,以了解你真正在做什么。
其他回答
我只是想补充一下这个讨论,我只是在VS和GCC上编译,并且习惯使用包含守卫。我现在已经切换到#pragma一次了,对我来说唯一的原因不是性能或可移植性或标准,因为我并不关心什么是标准,只要VS和GCC支持它,那就是:
#pragma一次性减少了出现错误的可能性。
将一个头文件复制并粘贴到另一个头文件,修改它以满足自己的需要,并且忘记更改include守卫的名称,这太容易了。一旦包含了两者,就需要花费一些时间来跟踪错误,因为错误消息并不一定是清晰的。
我回答了一个相关的问题:
#pragma once确实有一个缺点(除了不是标准的),那就是如果你在不同的位置有相同的文件(我们有这样的情况是因为我们的构建系统会四处复制文件),那么编译器会认为这些是不同的文件。
我把答案也加在这里,以防有人被这个问题绊倒,而不是其他问题。
如果你确信你永远不会在不支持它的编译器中使用这段代码(Windows/VS, GCC和Clang是支持它的编译器的例子),那么你当然可以使用#pragma一次而不用担心。
您也可以两者都使用(参见下面的示例),这样就可以在兼容系统上获得可移植性和编译加速
#pragma once
#ifndef _HEADER_H_
#define _HEADER_H_
...
#endif
直到#pragma成为标准的那一天(这不是未来标准的优先级),我建议你使用它并使用守卫,这样:
#ifndef BLAH_H
#define BLAH_H
#pragma once
// ...
#endif
原因如下:
#pragma once is not standard, so it is possible that some compiler don't provide the functionality. That said, all major compiler supports it. If a compiler don't know it, at least it will be ignored. As there is no standard behavior for #pragma once, you shouldn't assume that the behavior will be the same on all compiler. The guards will ensure at least that the basic assumption is the same for all compilers that at least implement the needed preprocessor instructions for guards. On most compilers, #pragma once will speed up compilation (of one cpp) because the compiler will not reopen the file containing this instruction. So having it in a file might help, or not, depending on the compiler. I heard g++ can do the same optimization when guards are detected but it have to be confirmed.
同时使用这两种编译器,可以充分利用每种编译器的优点。
现在,如果您没有一些自动脚本来生成守卫,那么只使用#pragma一次可能会更方便。要知道这对可移植代码意味着什么。(我使用VAssistX生成守卫和pragma一次快速)
你应该总是认为你的代码是可移植的(因为你不知道未来是由什么组成的),但如果你真的认为它不应该用另一个编译器编译(例如非常特定的嵌入式硬件的代码),那么你应该检查一下编译器文档中关于#pragma的内容,以了解你真正在做什么。
我不认为它会对编译时间产生重大影响,但#pragma once在所有编译器中都得到了很好的支持,但实际上并不是标准的一部分。预处理器可能会快一点,因为它更容易理解你的确切意图。
#pragma一次性使用不太容易出错,需要输入的代码也更少。
为了加快编译时间,尽可能地向前声明而不是包含在.h文件中。
我更喜欢使用#pragma一次。
这篇维基百科文章介绍了两者同时使用的可能性。