我读到使用#pragma once
会有一些编译器优化,可以加快编译速度。我知道这是非标准的,可能会在跨平台上造成兼容性问题。
大多数现代编译器在非 Windows 平台(如 gcc)是否支持这个优化呢?
我想避免平台编译问题,但也想避免额外的后备保护工作:
#pragma once
#ifndef HEADER_H
#define HEADER_H
...
#endif // HEADER_H
我应该关注吗?我是否应该继续花费精力在这件事上?
我读到使用#pragma once
会有一些编译器优化,可以加快编译速度。我知道这是非标准的,可能会在跨平台上造成兼容性问题。
大多数现代编译器在非 Windows 平台(如 gcc)是否支持这个优化呢?
我想避免平台编译问题,但也想避免额外的后备保护工作:
#pragma once
#ifndef HEADER_H
#define HEADER_H
...
#endif // HEADER_H
我应该关注吗?我是否应该继续花费精力在这件事上?
#pragma once
的一个缺点(除了不是标准的)就是如果您在不同的位置有相同的文件(我们有这种情况,因为我们的构建系统会复制文件),那么编译器将认为这些是不同的文件。
#ifdef
宏的值也可能不同。 - Motti使用#pragma once
应该可以在任何现代编译器上工作,但我认为使用标准的#ifndef
包含守卫也没有任何问题。它也能正常工作。唯一需要注意的是,在版本 3.4之前,GCC不支持#pragma once
。
我还发现,至少在GCC上,它会识别标准的#ifndef
包含守卫并进行优化,所以它的速度应该不会比#pragma once
慢多少。
#pragma once
一般更快,因为文件不需要进行预处理。 ifndef/define/endif
虽然也需要预处理,但是在这个块之后你可以有可编译的东西(理论上)。 - Andrey#ifndef FOO_BAR_H
,通常用于名为 "foo_bar.h" 的文件。如果稍后重命名此文件,是否应相应地调整包含保护以与此约定一致?而且,如果您的代码树中有两个不同位置的 foo_bar.h,则必须为每个文件想出两个不同的符号。简短的答案是使用 #pragma once
,如果您确实需要在不支持它的环境中编译,则继续为该环境添加包含保护。 - Brandin我希望标准库中有类似#pragma once
的东西。虽然头文件保护不是一个大问题(但是对于学习语言的人来说可能有点难以理解),但是它似乎是可以避免的小麻烦。
实际上,99.98%的情况下,防止重复包含头文件的行为都是所需的,因此如果编译器自动处理了这个问题,并提供了一个#pragma
或其他方式来允许重复包含头文件,那将非常好。
但我们现在只能使用现有的机制(除非你没有#pragma once
)。
#import
指令。 - John我不知道有没有性能优势,但它肯定是有效的。 我在所有我的C++项目中都使用它(尽管我正在使用MS编译器)。 我发现它比使用...更有效。
#ifndef HEADERNAME_H
#define HEADERNAME_H
...
#endif
它完成相同的工作,不会在预处理器中填充额外的宏。
GCC 官方支持 #pragma once,自3.4版本起。GCC自3.4版本开始支持#pragma once
,有关更多编译器支持信息,请参见http://en.wikipedia.org/wiki/Pragma_once
我认为使用#pragma once
而不是包含保护的主要优点是避免复制粘贴错误。
让我们面对现实吧:我们大多数人都很少从头开始创建一个新的头文件,而是只是复制一个现有的然后根据我们的需求进行修改。使用#pragma once
创建一个工作模板比使用包含保护要容易得多。我需要修改模板的次数越少,就越不可能遇到错误。在不同文件中使用相同的包含保护会导致奇怪的编译器错误,并且需要花费一些时间来找出问题所在。
简而言之:#pragma once
更容易使用。
我使用它并感到很满意,因为我需要输入的内容更少才能创建新的标题。我在三个平台上使用它都很好用:Windows、Mac和Linux。
我没有任何性能信息,但我相信 #pragma 和 include 声明防护的差别将无法与解析 C++ 语法时的速度慢相比。那才是真正的问题。例如,尝试使用 C# 编译器编译相同数量的文件和行,来看看差异。
最终,使用防护或者#pragma都不会有太大影响。
使用'#pragma once
'可能没有任何效果(它不受到普遍支持,尽管越来越多的编译器开始支持),因此您仍需要使用有条件的编译代码,在这种情况下,为什么要费劲地使用'#pragma once
'呢?编译器可能会自动优化它。但这要取决于您的目标平台。如果您的所有目标都支持它,请继续使用它,但这应该是一个慎重的决定,因为如果您仅使用#pragma而后移到不支持它的编译器上,则会出现问题。
#ifndef NR_TEST_H
#define NR_TEST_H
#pragma once
#include "Thing.h"
namespace MyApp
{
// ...
}
#endif
这样做可以兼顾跨平台和编译速度的优点。
由于输入较长,我个人使用一个工具来帮助快速生成代码(Visual Assist X)。
pragma
放在 ifndef
后面?有什么好处吗? - user1095108#pragma once
是非标准的,所以无论编译器决定做什么都是“正确”的。当然,我们可以开始讨论什么是“预期的”和什么是“有用的”。 - user7610X-Macro
功能中的观点,但这不是include的主要用途,如果我们坚持DRY原则,难道不应该采取另一种方式,比如头文件未保护/ #pragma multi吗? - caiohamamura
#pragma once
似乎可以避免VS 2008中的一些类视图问题。出于这个原因,我正在逐步取消所有的包含保护并将它们替换为#pragma once
。 - SmacL