Cppcoreguidelines: SF.8 and #pragma once

Created on 6 Aug 2017  路  14Comments  路  Source: isocpp/CppCoreGuidelines

SF.8 states:

Some implementations offer vendor extensions like #pragma once as alternative to include guards.
It is not standard and it is not portable. It injects the hosting machine's filesystem semantics into
your program, in addition to locking you down to a vendor. Our recommendation is to write in
ISO C++: See rule P.2.

As far as I know #pragmas are silently ignored if not supported by the compiler. I wonder if it is a good idea to use #pragma once and include guards together (and therefore worth to recommend).

Actually, I have seen it in the GSL:

#pragma once

#ifndef GSL_GSL_H
#define GSL_GSL_H

#include <gsl/gsl_assert>  // Ensures/Expects
:
:
#endif // GSL_GSL_H

Are there arguments against this approach?

Most helpful comment

Whatever you do, don't use both.

I would like to point out, that I see the main advantage of #pragma once not in any speed differences (that is probably more an historic anecdote), but in it's simplicity:

  • It clearly states intent to the human and the compiler
  • You don't have to worry about naming schemes and clashes
  • You don't have to keep the macro names in sync when changing the file name or moving it around
  • You are not introducing macro names into the lookup

But you lose all those advantages, as soon as you use both technique together.

Regarding the disadvantages:

  • #pragma once might be non-standard but it is supported by all compilers I (and probably the vast majority of c++ programmers) care about and quite frankly: There are a lot more compiler and platform specific assumptions encoded in most c++ projects than the availability of that extension.
  • Yes, it might lead to problems with some of the more complicated build infrastructures out there, but where those are deployed, you usually have an according set of coding guidelines specific for that environment anyway.

I'd find the case against #pragma once more convincing if there were more examples of when this lead to actual problems.

Personally, I tend to use include guards in library code, as I don't know, where this might end up in the end and #pragma once in application code. I haven't yet had a problem with this, but if one would arise, it is trivially to a script that replace #pragma once with include guards in a consistent manner.

All 14 comments

Simplicity.
I don't know we want to recommend "throw everything to the wall and see what sticks."

Thanks @gdr-at-ms. Simplicity is a good argument. Are there portability concerns I have overseen? E.g. compilers failing to silently ignore unknown #pragmas?

GCC (optionally) warns about unknown pragmas, that's what the -Wunknown-pragma warning is for. I expect Clang has the same warning. Both of them accept #pragma once, but clearly not all compilers silently ignore unknown pragmas, so it's not safe to assume that all compilers won't warn about it.

@franzhollerer pragma once injects the build/host's underlying filesystem vagaries into the semantics of the program. The include guard pattern only relies on the content.

@gdr-at-ms wrote:

pragma once injects the build/host's underlying filesystem vagaries into the semantics of the program.

Well, that's exactly the point I failed to follow in the argument against #pragma once. If the compiler supports pragma once, I don't care from the user point of view that the compiler relies on properties of the underlayig filesystem. There are dependencies to the file system anyway the compiler toolchain needs to deal with.

If the compiler complies to the standard and ingores unknown #pragmas then I see no problem either, provided that the header file also contains the include guard (as done in the GSL library).

Thus the best argument is a) simplicity and b) that some compilers fail to comply to the standard and don't silently ignore #unknown pragmas.

Beiing said, I see the point of SF.8 My feedback as reader of the C++ Core Rules is that I failed to figure out the details from the rational given in rule SF.8 (which for sure is due to lack of knowlege on my side).

Probably I failed to grasp the full concequence of the pragma once injects the build/host's underlying filesystem vagaries into the semantics of the program argument. But following SF.8 it might be a good idea to remove #pragma once from the GSL.

I found the following at https://en.wikipedia.org/wiki/Pragma_once.

It is important to note that some compilers such as GCC, Clang, and EDG-based compilers include specific optimizations to recognize and optimize the handling of include guards, and thus little or no speedup benefit is obtained from the use of #pragma once.

If this statement is correct it gives a good reason not to use pragma once.

That statement is correct, see for example https://gcc.gnu.org/onlinedocs/cpp/Once-Only-Headers.html

If your compiler doesn't do that, use a better compiler.

Whatever you do, don't use both.

I would like to point out, that I see the main advantage of #pragma once not in any speed differences (that is probably more an historic anecdote), but in it's simplicity:

  • It clearly states intent to the human and the compiler
  • You don't have to worry about naming schemes and clashes
  • You don't have to keep the macro names in sync when changing the file name or moving it around
  • You are not introducing macro names into the lookup

But you lose all those advantages, as soon as you use both technique together.

Regarding the disadvantages:

  • #pragma once might be non-standard but it is supported by all compilers I (and probably the vast majority of c++ programmers) care about and quite frankly: There are a lot more compiler and platform specific assumptions encoded in most c++ projects than the availability of that extension.
  • Yes, it might lead to problems with some of the more complicated build infrastructures out there, but where those are deployed, you usually have an according set of coding guidelines specific for that environment anyway.

I'd find the case against #pragma once more convincing if there were more examples of when this lead to actual problems.

Personally, I tend to use include guards in library code, as I don't know, where this might end up in the end and #pragma once in application code. I haven't yet had a problem with this, but if one would arise, it is trivially to a script that replace #pragma once with include guards in a consistent manner.

pragma once might be non-standard but it is supported by all compilers I (and probably the vast majority of c++ programmers) care about and quite frankly: There are a lot more compiler and platform specific assumptions encoded in most c++ projects than the availability of that extension.

This is only partially true.

IIRC, for example, in the presence of symlinks pragma-once (unlike once-guards) don't do the same thing on "all compilers people care about". This is precisely the kind of problem (quoth gdr "underlying filesystem vagaries") with pragma once that makes people unhappy to recommend it for truly portable C++.

@lbrandy: Maybe I'm extrapolationg too much from my own limited experience, but is it actually a common problem that you are deliberately looking up the same file at two different locations inside a single TU?

I don't want to advertise the usage of pragma once too much, because it obviously has it's limitations, but im honestly interested in how much problems it causes in practice.

Our focus here is to help C++ developers use effectively standard C++.

The question of the limitations of #pragma once is an interesting one; is it better answered in an appropriate setting?

Like maybe https://stackoverflow.com/questions/1143936/pragma-once-vs-include-guards

The fact there are reasonable arguments both for and against #pragma once should make it clear the question is not settled, and so it would not be appropriate for the guidelines to recommend a non-standard extension with debatable benefits.

Can we move on please?

Not before the title is corrected once and for all ;)

@martinmoene: typo in title fixed.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

beinhaerter picture beinhaerter  路  5Comments

qalpaq picture qalpaq  路  5Comments

JVApen picture JVApen  路  4Comments

vingeldal picture vingeldal  路  4Comments

RedDwarf69 picture RedDwarf69  路  3Comments