#pragma Once 是安全包含防护吗?

发布于 2024-07-18 03:51:33 字数 306 浏览 8 评论 0原文

我读到,使用 #pragma Once 时有一些编译器优化,可以加快编译速度。 我认识到这是非标准的,因此可能会造成跨平台兼容性问题。

非 Windows 平台 (gcc) 上的大多数现代编译器都支持此功能吗?

我想避免平台编译问题,但也想避免后备防护的额外工作:

#pragma once
#ifndef HEADER_H
#define HEADER_H

...

#endif // HEADER_H

我应该担心吗? 我是否应该为此花费更多的精力?

I've read that there is some compiler optimization when using #pragma once which can result in faster compilation. I recognize that is non-standard, and thus could pose a cross-platform compatibility issue.

Is this something that is supported by most modern compilers on non-windows platforms (gcc)?

I want to avoid platform compilation issues, but also want to avoid the extra work of fallback guards:

#pragma once
#ifndef HEADER_H
#define HEADER_H

...

#endif // HEADER_H

Should I be concerned? Should I expend any further mental energy on this?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(16

生生漫 2024-07-25 03:51:34

主要区别在于编译器必须打开头文件才能读取包含保护。 相比之下,pragma 会导致编译器跟踪该文件,并且当遇到同一文件的另一个包含时不执行任何文件 IO。 虽然这听起来可以忽略不计,但它可以轻松地扩展到大型项目,尤其是那些没有良好标题包含规则的项目。

也就是说,如今编译器(包括 GCC)足够聪明,可以像编译指示一样对待包含保护。 即他们不打开文件并避免文件 IO 损失。

在不支持 pragma 的编译器中,我见过有点麻烦的手动实现。

#ifdef FOO_H
#include "foo.h"
#endif

我个人喜欢 #pragma Once 方法,因为它避免了命名冲突和潜在的拼写错误的麻烦。 相比之下,它的代码也更优雅。 也就是说,对于可移植代码来说,两者兼有应该不会有什么坏处,除非编译器抱怨它。

The main difference is that the compiler had to open the header file to read the include guard. In comparison, pragma once causes the compiler to keep track of the file and not do any file IO when it comes across another include for the same file. While that may sound negligible, it can easily scale up with huge projects, especially ones without good header include disciplines.

That said, these days compilers (including GCC) are smart enough to treat include guards like pragma once. i.e. they dont open the file and avoid the file IO penalty.

In compilers that dont support pragma I've seen manual implementations that are a little cumbersome..

#ifdef FOO_H
#include "foo.h"
#endif

I personally like #pragma once approach as it avoids the hassle of naming collisions and potential typo errors. It's also more elegant code by comparison. That said, for portable code, it shouldn't hurt to have both unless the compiler complains about it.

熊抱啵儿 2024-07-25 03:51:34

只是更快的编译:如果您使用 ifdef/define 来使用包含保护,理论上编译器必须读取头文件并在每次包含它时进行检查。 但在实践中,编译器会看到你有结构“空白”-“#if条件”-大量代码-“#endif”-“空白”。 如果存在该模式,编译器将仅记住文件的路径和条件。 如果它遇到同一文件路径的另一个 #include,它只会检查条件,并且仅在此时条件为 false 时才打开文件。

无论您使用包含保护,还是根据某些功能标志不使用整个文件,这都有效。 如果您手动取消定义包含保护,它会起作用,因为您希望它包含两次。 因此与“pragma Once”相比,时间差异很小。 这在今天很常见,您实际上不必使用“pragma Once”来提高编译器性能。

Just about the faster compilation: If you use include guards using ifdef/define, in theory the compiler would have to read the header file and check every time it is included. But in practice, the compiler sees that you have the structure “white space” - “#if condition” - lots of code - “#endif” - “white space”. With tha pattern present, the compiler will remember just the path of the file, and the condition. If it encounters another #include for the same file path, it just checks the condition and only opens the file if at this point the condition is false.

This works, whether you use an include guard, or if the whole file is not used depending on some feature flag. And it works if you manually undefine the include guard because you want it included twice. So the time difference compared to “pragma once” is minimal. And this is so common today, you really don’t have to use “pragma once” for compiler performance.

情话墙 2024-07-25 03:51:33

#pragma Once 确实有一个缺点(除了非标准之外),那就是如果您在不同位置有相同的文件(我们这样做是因为我们的构建系统复制文件),那么编译器将认为这些是不同的文件。

#pragma once does have one drawback (other than being non-standard) and that is if you have the same file in different locations (we have this because our build system copies files around) then the compiler will think these are different files.

违心° 2024-07-25 03:51:33

使用#pragma Once 应该可以在任何现代编译器上工作,但我认为没有任何理由不使用标准的#ifndef include 保护。 它工作得很好。 需要注意的是,GCC 在 版本 3.4

我还发现,至少在 GCC 上,它识别标准 < code>#ifndef 包含防护并对其进行优化,因此它应该不会比 #pragma Once 慢很多。

Using #pragma once should work on any modern compiler, but I don't see any reason not to use a standard #ifndef include guard. It works just fine. The one caveat is that GCC didn't support #pragma once before version 3.4.

I also found that, at least on GCC, it recognizes the standard #ifndef include guard and optimizes it, so it shouldn't be much slower than #pragma once.

谈下烟灰 2024-07-25 03:51:33

我希望 #pragma Once (或类似的东西)已经在标准中。 包含守卫并不是什么大问题(但向学习该语言的人解释它们确实有点困难),但这似乎是一个可以避免的小烦恼。

事实上,由于 99.98% 的情况下,#pragma Once 行为是所需的行为,如果编译器可以通过 自动处理防止多次包含标头,那就太好了>#pragma 或允许双重包含的东西。

但我们拥有我们所拥有的(除了您可能没有#pragma Once)。

I wish #pragma once (or something like it) had been in the standard. Include guards aren't a real big deal (but they do seem to be a little difficult to explain to people learning the language), but it seems like a minor annoyance that could have been avoided.

In fact, since 99.98% of the time, the #pragma once behavior is the desired behavior, it would have been nice if preventing multiple inclusion of a header was automatically handled by the compiler, with a #pragma or something to allow double including.

But we have what we have (except that you might not have #pragma once).

神魇的王 2024-07-25 03:51:33

我不知道有什么性能优势,但它确实有效。 我在所有 C++ 项目中都使用它(假设我使用的是 MS 编译器)。 我发现它比使用它更有效

#ifndef HEADERNAME_H
#define HEADERNAME_H
...
#endif

它可以完成相同的工作并且不会使用额外的宏填充预处理器。

GCC 从版本 3.4 开始正式支持#pragma Once自版本 3.4 起。

I don't know about any performance benefits but it certainly works. I use it in all my C++ projects (granted I am using the MS compiler). I find it to be more effective than using

#ifndef HEADERNAME_H
#define HEADERNAME_H
...
#endif

It does the same job and doesn't populate the preprocessor with additional macros.

GCC supports #pragma once officially as of version 3.4.

黑白记忆 2024-07-25 03:51:33

GCC 从 3.4 开始支持#pragma Once,请参阅http://en.wikipedia.org/wiki/Pragma_once< /a> 以获得进一步的编译器支持。

我认为使用 #pragma Once 与包含防护相比的最大好处是可以避免复制/粘贴错误。

让我们面对现实吧:我们大多数人几乎不会从头开始创建一个新的头文件,而只是复制现有的头文件并根据我们的需要进行修改。 使用#pragma Once而不是包含防护来创建工作模板要容易得多。 我需要修改模板的次数越少,遇到错误的可能性就越小。 在不同的文件中使用相同的包含保护会导致奇怪的编译器错误,并且需要一些时间才能找出问题所在。

TL;DR:#pragma Once 更易于使用。

GCC supports #pragma once since 3.4, see http://en.wikipedia.org/wiki/Pragma_once for further compiler support.

The big upside I see on using #pragma once as opposed to include guards is to avoid copy/paste errors.

Let's face it: most of us hardly start a new header file from scratch, but rather just copy an existing one and modify it to our needs. It is much easier to create a working template using #pragma once instead of include guards. The less I have to modify the template, the less I am likely to run into errors. Having the same include guard in different files leads to strange compiler errors and it takes some time to figure out what went wrong.

TL;DR: #pragma once is easier to use.

盛装女皇 2024-07-25 03:51:33

我使用它并且对它很满意,因为我需要输入更少的内容来创建新的标题。 它在三个平台上对我来说运行良好:Windows、Mac 和 Linux。

我没有任何性能信息,但我相信与解析 C++ 语法的缓慢相比,#pragma 和 include 保护之间的差异微不足道。 这才是真正的问题。 例如,尝试使用 C# 编译器编译相同数量的文件和行,以查看差异。

最后,使用守卫或编译指示根本不重要。

I use it and I'm happy with it, as I have to type much less to make a new header. It worked fine for me in three platforms: Windows, Mac and Linux.

I don't have any performance information but I believe that the difference between #pragma and the include guard will be nothing comparing to the slowness of parsing the C++ grammar. That's the real problem. Try to compile the same number of files and lines with a C# compiler for example, to see the difference.

In the end, using the guard or the pragma, won't matter at all.

我的鱼塘能养鲲 2024-07-25 03:51:33

使用 '#pragma Once' 可能没有任何效果(并非所有地方都支持它 - 尽管它越来越广泛地支持),所以无论如何你都需要使用条件编译代码,在这种情况下,为什么还要麻烦与“#pragma Once”? 无论如何,编译器可能会对其进行优化。 不过,它确实取决于您的目标平台。 如果你的所有目标都支持它,那么就继续使用它 - 但这应该是一个有意识的决定,因为如果你只使用编译指示然后移植到不支持它的编译器,一切都会崩溃。

Using '#pragma once' might not have any effect (it is not supported everywhere - though it is increasingly widely supported), so you need to use the conditional compilation code anyway, in which case, why bother with '#pragma once'? The compiler probably optimizes it anyway. It does depend on your target platforms, though. If all your targets support it, then go ahead and use it - but it should be a conscious decision because all hell will break loose if you only use the pragma and then port to a compiler that does not support it.

沫离伤花 2024-07-25 03:51:33

性能优势在于读取 #pragma Once 后无需重新打开文件。 使用防护措施,编译器必须打开文件(这可能会花费大量时间)以获取不应再次包含其内容的信息。

这只是理论上的,因为对于每个编译单元,某些编译器将自动不打开没有任何读取代码的文件。

无论如何,并非所有编译器都是如此,因此理想情况下,跨平台代码必须避免 #pragma 一旦它根本不标准/没有标准化的定义和效果。 不过实际上,确实比守卫要好。

最后,您可以获得更好的建议,以确保您的编译器获得最佳速度在这种情况下,无需检查每个编译器的行为,就是同时使用 pragma Once 和 Guards。

#ifndef NR_TEST_H
#define NR_TEST_H
#pragma once

#include "Thing.h"

namespace MyApp
{
 // ...
}

#endif

这样您就可以充分利用两者(跨平台和帮助编译速度)。

由于打字时间较长,我个人使用一个工具来帮助以非常有效的方式生成所有内容(Visual Assist X)。

The performance benefit is from not having to reopen the file once the #pragma once have been read. With guards, the compiler have to open the file (that can be costly in time) to get the information that it shouldn't include it's content again.

That is theory only because some compilers will automatically not open files that didn't have any read code in, for each compilation unit.

Anyway, it's not the case for all compilers, so ideally #pragma once have to be avoided for cross-platform code has it's not standard at all / have no standardized definition and effect. However, practically, it's really better than guards.

In the end, the better suggestion you can get to be sure to have the best speed from your compiler without having to check the behavior of each compiler in this case, is to use both pragma once and guards.

#ifndef NR_TEST_H
#define NR_TEST_H
#pragma once

#include "Thing.h"

namespace MyApp
{
 // ...
}

#endif

That way you get the best of both (cross-platform and help compilation speed).

As it's longer to type, I personally use a tool to help generate all that in a very wick way (Visual Assist X).

欲拥i 2024-07-25 03:51:33

不总是。

http://gcc.gnu.org/bugzilla/show_bug.cgi?id=52566 有一个很好的示例,其中两个文件本应包含在内,但由于相同的时间戳和内容(不相同的文件名)而被错误地认为是相同的。

Not always.

http://gcc.gnu.org/bugzilla/show_bug.cgi?id=52566 has a nice example of two files meant to both be included, but mistakenly thought to be identical because of identical timestamps and content (not identical file name).

和我恋爱吧 2024-07-25 03:51:33

如今,老式的 include 守卫的速度与 #pragma 一次一样快。 即使编译器没有特殊对待它们,当它看到 #ifndef WHATEVER 和 WHATEVER 被定义时,它仍然会停止。 如今打开文件非常便宜。 即使有改善,也只是毫秒级的。

我只是不使用 #pragma 一次,因为它没有任何好处。 为了避免与其他包含防护发生冲突,我使用如下内容: CI_APP_MODULE_FILE_H --> CI = 公司缩写; APP = 应用程序名称; 其余的都是不言自明的。

Today old-school include guards are as fast as a #pragma once. Even if the compiler doesn't treat them specially, it will still stop when it sees #ifndef WHATEVER and WHATEVER is defined. Opening a file is dirt cheap today. Even if there were to be an improvement, it would be in the order of miliseconds.

I simply just don't use #pragma once, as it has no benefit. To avoid clashing with other include guards I use something like: CI_APP_MODULE_FILE_H --> CI = Company Initials; APP = Application name; the rest is self-explanatory.

非要怀念 2024-07-25 03:51:33

如果我们使用msvc或Qt(最高Qt 4.5),因为GCC(最高3.4),msvc都支持#pragma Once,我看不出有什么理由不使用#pragma Once< /代码>。

源文件名通常与类名相同,我们知道,有时我们需要重构,重命名类名,那么我们也必须更改#include XXXX,所以我认为手动维护#include xxxxx并不是一项聪明的工作。 即使使用 Visual Assist X 扩展,维护“xxxx”也不是必要的工作。

If we use msvc or Qt (up to Qt 4.5), since GCC(up to 3.4) , msvc both support #pragma once, I can see no reason for not using #pragma once.

Source file name usually same equal class name, and we know, sometime we need refactor, to rename class name, then we had to change the #include XXXX also, so I think manual maintain the #include xxxxx is not a smart work. even with Visual Assist X extension, maintain the "xxxx" is not a necessary work.

烟织青萝梦 2024-07-25 03:51:33

我使用 #ifndef/#define 包含防护,使用包含 UUID 的符号,如下所示:

#ifndef ARRAY__H_81945CB3_AEBB_471F_AC97_AB6C8B220314
#define ARRAY__H_81945CB3_AEBB_471F_AC97_AB6C8B220314 /* include guard */


#endif

我总是使用能够自动生成 UUID 的编辑器。
这可以防止与其他库中具有相同基本名称的文件发生名称冲突,并检测完全相同的文件是否放置在文件系统内的多个位置。

缺点是增加了表的大小,因为符号更大了,但我还没有看到它的问题。

I use #ifndef/#define include guards using symbols that incorporate a UUID like this:

#ifndef ARRAY__H_81945CB3_AEBB_471F_AC97_AB6C8B220314
#define ARRAY__H_81945CB3_AEBB_471F_AC97_AB6C8B220314 /* include guard */


#endif

I'v always used editors that were able to generate the UUIDs automatically.
This prevents name clash with files with the same base name from other libraries, and detects if the exact same file is placed in multiple locations inside the file system.

The down-side is the increase table size since the symbols are much bigger but I have not yet seen problems with it.

漫雪独思 2024-07-25 03:51:33

在非常大的树上使用 gcc 3.4 和 4.1(有时使用 distcc),我还没有看到任何使用 #pragma 一次代替标准包含防护或与标准包含防护结合使用时可以加快速度。

我真的不明白它有什么可能使旧版本的 gcc 甚至其他编译器感到困惑,因为没有真正的节省。 我还没有尝试过所有不同的去绒器,但我敢打赌这会让很多人感到困惑。

我也希望它早点被采用,但我可以看到这样的论点:“当 ifndef 工作得很好时,为什么我们需要它?”。 考虑到 C 的许多黑暗角落和复杂性,包含守卫是最简单、不言自明的事情之一。 如果您对预处理器的工作原理只有一点点了解,那么它们应该是不言自明的。

但是,如果您确实观察到明显的加速,请更新您的问题。

Using gcc 3.4 and 4.1 on very large trees (sometimes making use of distcc), I have yet to see any speed up when using #pragma once in lieu of, or in combination with standard include guards.

I really don't see how its worth potentially confusing older versions of gcc, or even other compilers since there's no real savings. I have not tried all of the various de-linters, but I'm willing to bet it will confuse many of them.

I too wish it had been adopted early on, but I can see the argument "Why do we need that when ifndef works perfectly fine?". Given C's many dark corners and complexities, include guards are one of the easiest, self explaining things. If you have even a small knowledge of how the preprocessor works, they should be self explanatory.

If you do observe a significant speed up, however, please update your question.

辞取 2024-07-25 03:51:33

对于那些认为总是需要自动一次性包含头文件的人来说,需要补充一点:几十年来,我一直使用两次或多次包含头文件来构建代码生成器。 特别是对于协议库存根的生成,我发现拥有一个极其便携且功能强大的代码生成器非常舒服,无需额外的工具和语言。 我不是唯一使用此方案作为 此博客 X-Macros 显示。 如果没有缺失的自动防护,这是不可能做到的。

Additional note to the people thinking that an automatic one-time-only inclusion of header files is always desired: I build code generators using double or multiple inclusion of header files since decades. Especially for generation of protocol library stubs I find it very comfortable to have a extremely portable and powerful code generator with no additional tools and languages. I'm not the only developer using this scheme as this blogs X-Macros show. This wouldn't be possible to do without the missing automatic guarding.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文