#pragma once vs include guards? [duplicate]
Asked Answered
D

13

468

I'm working on a codebase that is known to only run on windows and be compiled under Visual Studio (it integrates tightly with excel so it's not going anywhere). I'm wondering if I should go with the traditional include guards or use #pragma once for our code. I would think letting the compiler deal with #pragma once will yield faster compiles and is less error prone when copying and pasting. It is also slightly less ugly ;)

Note: to get the faster compile times we could use Redundant Include Guards but that adds a tight coupling between the included file and the including file. Usually it's ok because the guard should be based on the file name and would only change if you needed to change in the include name anyways.

Delftware answered 17/7, 2009 at 15:18 Comment(0)
R
427

I don't think it will make a significant difference in compile time but #pragma once is very well supported across compilers but not actually part of the standard. The preprocessor may be a little faster with it as it is more simple to understand your exact intent.

#pragma once is less prone to making mistakes and it is less code to type.

To speed up compile time more just forward declare instead of including in .h files when you can.

I prefer to use #pragma once.

See this wikipedia article about the possibility of using both.

Rogers answered 17/7, 2009 at 15:21 Comment(18)
According to wikipedia, some compilers optimize pragma once, some (like gcc) also optimize include guards. My gut says go with whatever system your code is already using. I use BOTH pragma once and guards.Hightoned
It can make a significant difference in compile time because the C preprocessor doesn't have to be involved - the compiler itself can decide not to even open the file. Opening files over and over takes cycles.Insight
@Donnie - that is the optimisation which gcc's preprocessor applies to include guards. It automatically detects include guards in header files, and if there is one it treats the file as though it had #pragma once. If it's included again, and the include guard has not been undefined in the mean time, then the file is not re-opened or re-parsed.Efflux
True, but the question poster is using VC++, so using #pragma once may result in faster compilation.Insight
Oh, I see what you mean. Sorry, I thought you were responding to kts's comment. About "some compilers (like gcc)". Clearly you're in fact responding to Brian's first sentence. Ignore me.Efflux
I put that bit about "some compilers" because I do not know what VC++ does (since I use both pragma once and guards) it has never mattered, and because MS could decide to remove/change pragma once behavior since it isn't required by the standard. Why they might do this I don't know, but it wouldn't be the first time they've made old code incompatible with new versions of Visual Studio.Hightoned
About forward declaring (Another thing that doesn't get mentioned so often): while decreasing compile time, be aware that if you ever want to refactor the forward declared class - e.g. change its name or namespace - all those forward declarations come back at you as you need to change each single one. And they don't even produce clear compiler errors as the forward declaration remains valid. So Ctrl Shift F it is, but boohoo if you declared the same name in a lot of different namespaces... just a side note that forward declarations also have downsides (I do use them still)Archicarp
#pragma once is not reliable (different file hierarchy perspectives (current-working-directories), soft and hard links, network filesystems, and even name collision --try with a file named string.h or something like that--). Not taking into account speed, you could have a script that substituted any, say, %INCLUDE_GUARD% in a file for an automatically-managed guard symbol; you would write headers as header.hpp.in, and, because you would already have the preprocessor conditional pair, the final header would not flow and the compiler would emit the correct line numbers in diagnostics.Entrench
I just learned the hard way that pragma once is not reliable. (thanks for confirmation, @Kalrish) Header guards did work where pragma once didn't. (on MSVC10) I'm now using both.Eutrophic
I've never had issues with pragma once, however, I've had issues with include guards. I tried a very basic test: 1. Create two folders, "my" and "your", 2. add the files ifdef.h and pragma.h to both folders, 3. include guard the ifdefs with IFDEF_H and the pragma's with pragma once. 4. define MY_IFDEF, YOUR_IFDEF, MY_PRAGMA, YOUR_PRAGMA, in each respective file in the guarded areas. 5. include all in a test.cpp file. 6. ifdef test for each, cout'ing on exists or non-exists. I found the pragma once defines existed, however one of the ifdef defines did not. When does pragma once fail?Attlee
I don't understand the alleged reliability problem with #pragma once. If I have two different headers foo/string.h and bar/string.h then putting a #pragma once means I'm allowed to include each of them once, but including both of them is also OK. If I use an include guard, then I will probably write something like #ifndef STRING_H in both files - which means I can't include both foo/string.h and bar/string.h.Kinsella
@Kinsella If you have two files both named string.h, you're probably going to end up with internal name collisions if you haven't used namespaces anyway as two files with that name are both likely to do something involving strings, and if you use namespaces, in my opinion, you should include the namespace in the include guard identifier.Stereotaxis
@Kinsella But that's entirely within your control (read: simply don't do that; why would you do that?). Running into reliability problems with #pragma once (which are well-documented) may be largely outside of your control.Continuum
@LightnessRacesinOrbit Probably those names were not good examples. You could imagine though a big project with several components, each having a common header with a conventional name e.g. "constants.h", so you end up with comp1/constants.h, comp2/constants.h, .... But each component author won't really be thinking about how her component will be included along with others, so probably she will just write her include guard as #ifdef INCLUDED_CONSTANTS_H or something like that. E.g. the standard way easily leads to an include guard name clash.Kinsella
@Brian R. Bondy also #pragma once does not do a sanity check so essentially you can create a circular dependency and never even know it, take GLM lib for example type_mat2x2.hpp includes its .inl file, type_mat2x2.inl includes func_matrix.hpp, func_matrix.hpp includes mat2x2.hpp, mat2x2.hpp includes type_mat2x2.hpp, this is 100% a circular dependency because at the end type_mat2x2.hpp is included into itself, however since they use #pragma once instead of include guards, the compiler removed the include and allows the code to function properly allowing a dangerous bug to slipDian
@Kinsella you should never have name clashes in your own projects. As JAB points out, namespaces should be used to disambiguate reusable components; alternatively, you can use physical package design (a requirement in Java) to disambiguate. In both cases, systematically including the namespace name or package path in the include guard will eliminate any potential clashes. See this article to see a real-world example of physical design and include guards.Finny
@Moebius Namespaces do not apply to preprocessor symbols e.g. in the above example it is likely that both files would have INCLUDED_CONSTANTS_H or something like that for a traditional include guard, even though they are distinct files. Of course you could disambiguate by naming your symbols more fully, e.g. INCLUDED_COMP1_CONSTANTS_H and INCLUDED_COMP2_CONSTANTS_H but in practice no one does that.Kinsella
I understand Brandin. I’m suggesting that if you have a package called ABC and a package called DEF, with or without explicit use of the namespace declaration, your include guards could be INCLUDED_ABC_CONSTANTS and INCLUDED_DEF_CONSTANTS to avoid a clash. Also, calling the header files abc_constants.h and def_constants.h improves comprehension and avoids some potentially nasty checkin errors.Finny
A
214

I just wanted to add to this discussion that I am just compiling on VS and GCC, and used to use include guards. I have now switched to #pragma once, and the only reason for me is not performance or portability or standard as I don't really care what is standard as long as VS and GCC support it, and that is that:

#pragma once reduces possibilities for bugs.

It is all too easy to copy and paste a header file to another header file, modify it to suit ones needs, and forget to change the name of the include guard. Once both are included, it takes you a while to track down the error, as the error messages aren't necessarily clear.

Archicarp answered 22/7, 2011 at 16:55 Comment(2)
This is the correct reason. Forget performance—we should use #pragma once because it’s less error prone. It occurs to me that if compilers are already tracking include guards, they’re already doing most of the work necessary to issue warnings when they see different files using the same macro name.Pergrim
just to tell it as i have experienced that exact issue this day. The compiler might just not accept a type you have created and you just sitting there wondering why the type is not found by the compiler as you have included correctly and you have also added the files to your build script (in my case cmake) you really need a while until you realize that you had copied the header file and forgot to change the include guard.Eider
E
178

#pragma once has unfixable bugs. It should never be used.

If your #include search path is sufficiently complicated, the compiler may be unable to tell the difference between two headers with the same basename (e.g. a/foo.h and b/foo.h), so a #pragma once in one of them will suppress both. It may also be unable to tell that two different relative includes (e.g. #include "foo.h" and #include "../a/foo.h" refer to the same file, so #pragma once will fail to suppress a redundant include when it should have.

This also affects the compiler's ability to avoid rereading files with #ifndef guards, but that is just an optimization. With #ifndef guards, the compiler can safely read any file it isn't sure it has seen already; if it's wrong, it just has to do some extra work. As long as no two headers define the same guard macro, the code will compile as expected. And if two headers do define the same guard macro, the programmer can go in and change one of them.

#pragma once has no such safety net -- if the compiler is wrong about the identity of a header file, either way, the program will fail to compile. If you hit this bug, your only options are to stop using #pragma once, or to rename one of the headers. The names of headers are part of your API contract, so renaming is probably not an option.

(The short version of why this is unfixable is that neither the Unix nor the Windows filesystem API offer any mechanism that guarantees to tell you whether two absolute pathnames refer to the same file. If you are under the impression that inode numbers can be used for that, sorry, you're wrong.)

(Historical note: The only reason I didn't rip #pragma once and #import out of GCC when I had the authority to do so, ~12 years ago, was Apple's system headers relying on them. In retrospect, that shouldn't have stopped me.)

(Since this has now come up twice in the comment thread: The GCC developers did put quite a bit of effort into making #pragma once as reliable as possible; see GCC bug report 11569. However, the implementation in current versions of GCC can still fail under plausible conditions, such as build farms suffering from clock skew. I do not know what any other compiler's implementation is like, but I would not expect anyone to have done better.)

Exclusive answered 19/1, 2016 at 18:52 Comment(50)
On technical level I agree with you, but if the two include guards have the same name, because the files have same name (which is quite likely), there's nothing won. Am I mistaken?Afrikah
@Afrikah "If two headers do define the same guard macro, the programmer can go in and change one of them."Exclusive
FYI this answer is being discussed on Reddit. People aren’t convinced by your arguments (and I think they have a point).Gorga
If the files have the same content, maybe they are the same file? I think this should be good enough, no need to mess with inode numbers or other hacks...Eyde
@Eyde Remember that in general C declarations are not idempotent. Including the same file twice, or two files with identical contents, will usually cause compilation to fail. Except when including the same file twice is exactly what the programmer wanted and not doing it will cause compilation to fail. Figuring out which case you're in is probably equivalent to the Halting Problem.Exclusive
@KonradRudolph I was wondering why it was suddenly attracting more votes. I don't have the time to attempt to persuade people any more than I already have; if they're not convinced, oh well.Exclusive
"If your #include search path is sufficiently complicated, the compiler may be unable to tell the difference between two headers with the same basename (e.g. a/foo.h and b/foo.h), so a #pragma once in one of them will suppress both. " could you provide a source for this ?Mucus
@Jean-MichaëlCelerier Unfortunately, I can't tell you more precisely than "dig through the GCC mailing lists and bug tracker circa 2001-2004 for problems with #import and/or #pragma once." It was a long time ago.Exclusive
@Exclusive "Except when including the same file twice is exactly what the programmer wanted and not doing it will cause compilation to fail." That doesn't seem to be a problem to me, because such a file wouldn't have an include guard except in rare edge cases. Such cases could simply be resolved by not using #pragma once for that file.Bensky
@JordanMelo I feel like we're in "The compiler cannot tell what you meant it to do" territory here. Don't imagine that you are trying to fix an application that tripped over the bugs I outlined. Instead, imagine you are trying to implement #pragma once. How do you make it behave reasonably in the face of arbitrary, unknown, unpredictable in advance include paths and macro hackery, given only the information available to a compiler, in particular, not the contents of the application programmer's mind?Exclusive
@JordanMelo To put it another way: If you are the compiler programmer you do not get to handwave away "rare edge cases".Exclusive
@Exclusive I found this bug report from 2003 : gcc.gnu.org/bugzilla/show_bug.cgi?id=11569 ; it says at the end : #pragma once has been undeprecated in 3.4 because it [gcc] contains a correct implementation at last.. So the damn things works perfectly since about 13 years and yet FUD is still spread ?Mucus
@Jean-MichaëlCelerier That refers to gcc.gnu.org/ml/gcc-patches/2003-07/msg02780.html in which Neil Booth thought he had succeeded in implementing the damn thing correctly, but, reading the code and the subsequent thread, he did not address all of the corner cases I was thinking of when I posted this. The most probable failure case is a false negative (file included twice when it should not have been) in the presence of a network file system whose last-modification timestamps are self-inconsistent.Exclusive
@Jean-MichaëlCelerier (If you don't think a network file system whose last-modification timestamps are self-inconsistent is a scenario worth worrying about, I envy the life you must have lead.)Exclusive
@Exclusive If you don't think a network file system whose last-modification timestamps are self-inconsistent is a scenario worth worrying about, I envy the life you must have lead. I run into this at work every day of the week, every single time I compile. It's not a corner case. If anything the corner case would be that the last-modification timestamps would be consistent when using a network file system. Having said this, I always use #pragma once, and never ran into an issue with it. I understand it cannot be implemented reliably, but if you don't do dumb stuff you are ok.Elston
If you have an identical include file, there's no point in including it many times, iff it has a #pragma once inside of it. This behavior should IMHO be standardized. Implementations using a pair (file size, crypto digest) would be "close enough" I think. The source of the file doesn't matter then: it can be fed over a pipe, over standard input, a web socket, whatever. If the preprocessor reads it as a "file", and it has the pragma, and it's identical to another "file" previously read, it's ignored. Easy peasy.Keos
@KubaOber You have missed the possibility that A/foo.h and B/foo.h might be textually identical, but included (as #include "foo.h"), by A/bar.h and B/bar.h respectively, with different macro definitions in effect. You might think that this is too farfetched to worry about, but as I said earlier, compiler authors do not get to dismiss anything as too farfetched to worry about.Exclusive
@KubaOber (I don't even think it's that farfetched, me. I suspect there are bits of the Boost preprocessor library that you use exactly like that.)Exclusive
@Exclusive That's OK, if you do it then it shouldn't have #pragma once :) Again, one has to define some sort of sane semantics for that pragma. If you want to include the same thing multiple times, don't put the #pragma once inside :)Keos
@KubaOber I'm just going to keep repeating "compiler authors do not get to dismiss anything as too farfetched to worry about" until the full implications sink inExclusive
@Exclusive I'm sorry but if A/foo.h and B/foo.h are identical and have include guards, then by necessity the include guards are identical too and the second inclusion will still be a ignored no matter what macro definitions are in effect, unless these definitions somehow change the meaning of the include guard (can they? do they?). Boost sources that are meant to be included multiple times for preprocessor "computation" purposes don't have include guards IIRC, it'd be nonsensical for them to have them. So, unless I don't understand you, I don't think it's a real problem.Keos
@KubaOber Please accept for the sake of the hypothetical that there is a header file foo.h that should be once-only, and that depends on macros defined by the file that includes it. Imagine that this header is copied into two libraries, A and B, which use it differently, and that both libraries are then copied into a larger program. Under either #ifndef guards or your proposed semantic for #pragma once, this will break. But with #ifndef guards, there is an obvious fix which the person maintaining the larger program can apply without affecting anything else: change the guard macros.Exclusive
@KubaOber In contrast, with your proposed semantic for #pragma once, there is also a fix -- change any text in a comment, say -- but it's not obvious from code inspection, the maintainer is going to have to look it up in the manual and then worry about whether that works in all supported compilers. #ifndef guards are therefore a better language feature in terms of user experience.Exclusive
@Exclusive So, the workaround is always to modify the file, except that include guards make it more obvious?Keos
@KubaOber Right. But note that this applies only to your semantics for #pragma once. A more pathname-oriented semantic might require you to rename a file in case of a conflict, and that might break an API contract. And compilers have not historically been good at documenting exactly how they implement this stuff, so how would you know what to do? I am thinking about how I might revise my answer to express these things better.Exclusive
I don't think that there's any way to make pathnames work in a way that's easy to specify and feasible to implement on a random platform. If one were to standardize the behavior of #pragma once, the term "path" shouldn't even be mentioned. Include guards don't use paths either, other than the humans usually putting a mangled path there and praying that it doesn't clash with anything.Keos
You described situation where pragma once will fail, but #ifndef also. So what is the point. You have to change content of file. If you use prama once everywhere, you add #ifndef to your files and that's it. If you are using #ifndef everywhere, you change it. If you have specific need for some files #ifndef is what you can use, using pragma once wont disable this possibility.Summertime
@Summertime His point is that "you need to change the file's contents" is more obvious with normal include guards, and depending on how a particular compiler implements it, might not be enough to guarantee success with #pragma once. Basically, for include guards, you can tell at a glance that you need to change one of the guards; with #pragma once, though, you need to look through the compiler's documentation to see whether you need to change the file's contents, change its name, or what.Superego
So, in effect, it's that one has a more obvious fix, and that the logical fix might not actually be enough for the other (depending on the compiler).Superego
I never had problems with #pragma once. I only had problems with #ifndef. Usually when I rename file and then create new with automatically generated #ifndef. which is already there, because I did rename file, not the safety guards. Ok #pragma once has bug, which is really rare I think. And it is solvable by modifying file. Just like problems with #ifndef. I still cannot see the point why not to use them. Nothing is 100% perfect.Summertime
GCC fixed the filename approach with correct symlink handing 13 years before this "answer" was posted. Even without filenames or inodes, it's still trivially fixed by using checksums. EDIT: gcc.gnu.org/bugzilla/show_bug.cgi?id=11569Jeanettajeanette
@Jeanettajeanette I refer you to my response to Jean-Michaël Celerier well upthread. They thought they fixed it, but they did not.Exclusive
Any solution based on filenames is an inherently useless waste of time, no further discussion of any filename or path based solutions is necessary. Now, A checksum of the file will not only be consistent across network drives with clock skew, but will even be consistent between duplicates with entirely different names and paths. This correctly implements the only sane use of #pragma once, which is to organize data structure definitions using redundant include trees. Calling this an "unfixable bug" is biased or naive, and the "arbitrary unpredictable" paths roadblock is a red herring.Jeanettajeanette
@Jeanettajeanette Checksums are not an option, as they will break real-world existing uses of the pragma that expect more pathname-like semantics. I also reiterate that as the compiler author you do not get to declare your customers' existing codebases "not sane", no matter how insane you think they are.Exclusive
That premise is a fallacy! Ok, "not sane" is an opinion and so you absolutely do get to declare anyone's codebase as sane or not. The "once" pragma is not rigidly standardized, and so technically an arbitrary choice is valid. As you said above: You could have ripped it out entirely years ago, definitely breaking many more codebases than just switching to checksums. This question explicitly asks about mitigating redundant includes, a common and useful task in programming, not obscure abuses of "once" that, as you said, should have been broken and re-written more robustly a long time ago.Jeanettajeanette
@Jeanettajeanette You are welcome to get in your time machine and go back to 2002 and have an argument with my then-boss about whether the customers' code needs to be supported.Exclusive
Why can't inode numbers be used? The combination of inode and device number is unique for every file on the system.Dysphonia
@Dysphonia Sadly, that is not true; you cannot count on inode or device numbers remaining stable over a filesystem dismount and remount (and yes, that can happen in the middle of a compilation run).Exclusive
@Exclusive If you remount files system during compilation, behaviour is undefined, just as behaviour is undefined if you change any files during compilation. That's not really a problem.Dysphonia
@Dysphonia Like I said to MickLH, you are welcome to get in your time machine and go back to 2002 and have an argument with my then-boss about whether the customers' code needs to be supported, except s/code/build farm/.Exclusive
"As long as no two headers define the same guard macro..." is an unfixable bug.Deplorable
@DanielStevens If two headers define the same guard macro, one of the macros can be renamed without affecting anything else. If two headers have a name conflict of the type that causes #pragma once to get confused, and you insist on continuing to use #pragma once, you have to rename one of the headers, which is probably an API break and therefore not possible.Exclusive
That misses the point. Macro names globally affect a compilation unit, even if headers come from separate individually developed libraries, written by separate authors. There is no way for the library writers to reasonably coordinate such a rename, forcing the change onto users of the library. Having to make source code modifications to 3rd party libraries greatly increases the maintenance burden of using those libraries. Neither header guards nor #pragma once are a proper module system.Deplorable
@DanielStevens Yes, neither of these things are a proper module system, but I think you overstate the difficulty of keeping header guard macro names from conflicting with each other, or with names used for other purposes. I've encountered such conflicts ... twice in 20 years, if I remember correctly, and neither involved third-party library headers. #pragma once malfunctions, on the other hand, were an ongoing problem for my entire tenure at the job with the build farm with the unreliable clocks (see above).Exclusive
@Enerccio I am disappointed to hear that you consider concerns over the reliability of a feature, under conditions actually encountered in the real world, to be characteristic of "diva OSS developer" behavior.Exclusive
@Exclusive there are primitive ways to improve #pragma once even on the craziest FS that is totally unreliable. For instance, hash the whole file and check against that. #pragma once is way more logical way to implement "header guards" than a block scoped macro definition that is obnoxious to modify. Also, I would really like to know those real life conditions where two separate files have same canonical path on a FS...Mella
@Mella That's what the current implementation in GCC does ... and you can still break it if you try hard enough! You probably think this is easy because you haven't ever seen a codebase with a genuinely complicated include search path. Please understand that my position is the result of spending literal years of my life trying and failing to make #pragma once as reliable as $former_employer's customers wanted it to be.Exclusive
@Exclusive so just because you had a rare breakage [that is very obvious what is wrong and easy to fix] you want to remove feature for everyone?Mella
@Mella All I can say is that I think you are grossly underestimating both the probability of a failure and the difficulty of fixing it.Exclusive
I ran into exactly this problem, using includes in includes in a header only library. This answer is definitely valid.Oxalis
D
45

Until the day #pragma once becomes standard (that's not currently a priority for the future standards), I suggest you use it AND use guards, this way:

#ifndef BLAH_H
#define BLAH_H
#pragma once

// ...

#endif

The reasons are :

  • #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.

Using the two together you get the best of each compiler for this.

Now, if you don't have some automatic script to generate the guards, it might be more convenient to just use #pragma once. Just know what that means for portable code. (I'm using VAssistX to generate the guards and pragma once quickly)

You should almost always think your code in a portable way (because you don't know what the future is made of) but if you really think that it's not meant to be compiled with another compiler (code for very specific embedded hardware for example) then you should just check your compiler documentation about #pragma once to know what you're really doing.

Damarisdamarra answered 17/7, 2009 at 15:45 Comment(15)
Who said that #pragma once is ever going to be standard? Also, how many compilers don't track if the header file is completely surrounded in include guards? In otherwords - has anybody measured if #pragma once actually makes a difference in reality?Waldos
@Richard, I have, and it does in cases - our project had 5500 includes with about 1/2 redundant.Postiche
@Richard Yes performace have been tested by many people, the optimisation is at least present in VC and gcc. I didn't say that #pragma once will be standart, it's just a very big possibility as the standardisation process often consist of standardizing common feature/usage that are proven to be efficient, like #pragma once.Damarisdamarra
@280Z28: Obviuosly a complete rebuild of 5500 includes with 50% being redundant is going to cost something. However, can you provide numbers, ie. using the pragma once compilation time (clean if you like) versus not using it. If you reach more than 1% of your total compliation time for a completely clean build I would be shocked.Waldos
@Klaim: What you said was - "Until #pragma once becomes standard". The until there implies that it is going to happen but it is just a matter of time. However, C++ '0x has been in the works now for quite some time, and there have been discussions on the usual news groups about the standardisation of the feature. The conclusion was that an existing mechanism exists and so there was no need to add an alternative way of doing the same thing.Waldos
@Klaim, 280Z28: Regarding performance, check out the following: gamesfromwithin.com/?p=32. Do either of you have numbers for a real project that show complete compile times for the project with and without #pragma once?Waldos
@Richard - I'll fix the "until" problem as it seem to not be obvious, I just wanted to say that if it's standardized one day, then it will not be necessary to use the guards. For the performance numbers, I don't have some for my current home projects, but we did some after changing some company source code to use pragma once. The compilers were VC9/9 and CodeWarrior. I don't have the exact member but we had somethink like 10% speed compilation improvement. I'm not sure this is interesting, I think we can find numbers on the web or make some test yes, I'll try if I find enough time.Damarisdamarra
By the way, the link you provide seems correct because the tests were made on "old" compiler, old enough to not have (Ithink) the optimizations we're talking about. A new test with recent compilers (vc8/9, last g++) would be a good thing indeed, to be sure about that. I agree that we should provide numbers, I don't have some right now.Damarisdamarra
"The until there implies that it is going to happen but it is just a matter of time" -- No it doesn't. This is a case of faux pedantry; someone pretending expertise who not only lacks it but hasn't applied even a minimal amount of thought or effort. And I will believe this until he shows up on my doorstep and proves me wrong.Fraction
What is the reason for having #pragma once after the include guard?Arawn
@DarioP: Compilers that recognize it don't care. Compilers that don't recognize it are at risk of disabling include guard optimization when there's stuff outside the include guard. And compilers without optimization will skip everything inside the guard on repeated includes, so less processing involved for what's inside.Tighten
Microsoft seems to have optimized their compiler. From Microsoft's VS2015 documentation: "There is no advantage to use of both the #include guard idiom and #pragma once in the same file. The compiler recognizes the #include guard idiom and implements the multiple include optimization the same way as the #pragma once directive if no non-comment code or preprocessor directive comes before or after the standard form of the idiom" msdn.microsoft.com/en-us/library/4141z1cx.aspxDiscompose
The "#pragma once" here will never been properly evaluated so is redundant because the guard will always override it. Don't bother, just use the old fashioned guard or only pragma once on a simpler project.Amalburga
@hookenz: How has it not been properly evaluated? On the first pass through the file, it's definitely evaluated. If the compiler has special handling for #pragma once, that's enough to get the necessary effect (it never tries to reparse the header). For a compiler with no specific optimizations for include guards (so it always reopens, rereads, reparses, and throws away the header on subsequent includes) where #pragma once is optimized (possibly preventing reopening the file at all, though it may stat it or even checksum it), it's logically redundant, but performance-wise important.Coordination
I wrote that comment a long time ago. I guess it's redundant because the #define will always work. The pragma is possibly less portable. But you do have a point that perhaps there could be some optimization using pragma. If true I'd put pragma at the top outside the other guard.Amalburga
D
44

From a software tester's perspective

#pragma once is shorter than an include guard, less error prone, supported by most compilers, and some say that it compiles faster (which is not true [any longer]).

But I still suggest you go with standard #ifndef include guards.

Why #ifndef?

Consider a contrived class hierarchy like this where each of the classes A, B, and C lives inside its own file:

a.h

#ifndef A_H
#define A_H

class A {
public:
  // some virtual functions
};

#endif

b.h

#ifndef B_H
#define B_H

#include "a.h"

class B : public A {
public:
  // some functions
};

#endif

c.h

#ifndef C_H
#define C_H

#include "b.h"

class C : public B {
public:
  // some functions
};

#endif

Now let's assume you are writing tests for your classes and you need to simulate the behaviour of the really complex class B. One way to do this would be to write a mock class using for example google mock and put it inside a directory mocks/b.h. Note, that the class name hasn't changed but it's only stored inside a different directory. But what's most important is that the include guard is named exactly the same as in the original file b.h.

mocks/b.h

#ifndef B_H
#define B_H

#include "a.h"
#include "gmock/gmock.h"

class B : public A {
public:
  // some mocks functions
  MOCK_METHOD0(SomeMethod, void());
};

#endif

What's the benefit?

With this approach you can mock the behaviour of class B without touching the original class or telling C about it. All you have to do is put the directory mocks/ in the include path of your complier.

Why can't this be done with #pragma once?

If you would have used #pragma once, you would get a name clash because it cannot protect you from defining the class B twice, once the original one and once the mocked version.

Debbradebby answered 13/11, 2014 at 11:38 Comment(8)
This is not practical for any large project. Keep B up2date will be pain and not to mention this violates the One Definition RuleAlleyne
@parapurarajkumar The ODR is not violated because if your include mocks/b.h before b.h the preprocessor will skip b.h entirely leaving you with only one class B. I wonder if you have a less "painful" approach for testing class B. What strategy do you propose for testing "any large project"?Debbradebby
But there will be other parts of the system i.e. non test code where you can not override gmock.h ?Alleyne
Nobody is overriding "gmock.h". It is part of the Testframework with which we want to simulate a class. I think we're talking about two different things. The whole point is to take existing code or a class hierarchy and as a test replace one part of the chain with a simulator or mocking class. This way you are effectively testing non-testing code. It is not like a unit test where you only test one class on its own but what mocking allows you to do is system testing. And if your class hierarchy uses classical #ifndef include guards you can replace a class with a mock just in your test.Debbradebby
Hmm, if both the original b.h and the mock b.h are in the compiler include paths - won't there be a name clash with #include "b.h"? If you remove the original b.h path from the include directories for the test project so that only the mock b.h is picked up, then won't #pragma once also work?Discommode
@Discommode These are all headers, we have not seen how they are included in compiled code. I would imagine the real cpp would #include "c.h", while the test code would do something like #include "mocks/b.h" then #include "c.h" or maybe the real code does #include <b.h> then #include <c.h> where include path order matters. c.h would still include local b.h and not mocks/b.h because of "" and not <>. But I might be wrong.Pm
You also can't do this when using #pragma once by add code like namespace mock_b {#include "b.h"} in your mocks/b.h. Since the including is pre-process, which ignores namespace, it prevents a.h to include b.h and puts real class B in a different namespace without name clash with mock Class BKoenraad
IMO if you're adding mocks/b.h to the include path, you should also remove the original b.h instead of depending the include guards. Your solution is just as lame as symbol interposition :-/Linebreeding
G
30

After engaging in an extended discussion about the supposed performance tradeoff between #pragma once and #ifndef guards vs. the argument of correctness or not (I was taking the side of #pragma once based on some relatively recent indoctrination to that end), I decided to finally test the theory that #pragma once is faster because the compiler doesn't have to try to re-#include a file that had already been included.

For the test, I automatically generated 500 header files with complex interdependencies, and had a .c file that #includes them all. I ran the test three ways, once with just #ifndef, once with just #pragma once, and once with both. I performed the test on a fairly modern system (a 2014 MacBook Pro running OSX, using XCode's bundled Clang, with the internal SSD).

First, the test code:

#include <stdio.h>
 
//#define IFNDEF_GUARD
//#define PRAGMA_ONCE
 
int main(void)
{
    int i, j;
    FILE* fp;
 
    for (i = 0; i < 500; i++) {
        char fname[100];
 
        snprintf(fname, 100, "include%d.h", i);
        fp = fopen(fname, "w");
 
#ifdef IFNDEF_GUARD
        fprintf(fp, "#ifndef _INCLUDE%d_H\n#define _INCLUDE%d_H\n", i, i);
#endif
#ifdef PRAGMA_ONCE
        fprintf(fp, "#pragma once\n");
#endif
 
 
        for (j = 0; j < i; j++) {
            fprintf(fp, "#include \"include%d.h\"\n", j);
        }
 
        fprintf(fp, "int foo%d(void) { return %d; }\n", i, i);
 
#ifdef IFNDEF_GUARD
        fprintf(fp, "#endif\n");
#endif
 
        fclose(fp);
    }
 
    fp = fopen("main.c", "w");
    for (int i = 0; i < 100; i++) {
        fprintf(fp, "#include \"include%d.h\"\n", i);
    }
    fprintf(fp, "int main(void){int n;");
    for (int i = 0; i < 100; i++) {
        fprintf(fp, "n += foo%d();\n", i);
    }
    fprintf(fp, "return n;}");
    fclose(fp);
    return 0;
}

And now, my various test runs:

folio[~/Desktop/pragma] fluffy$ gcc pragma.c -DIFNDEF_GUARD
folio[~/Desktop/pragma] fluffy$ ./a.out 
folio[~/Desktop/pragma] fluffy$ time gcc -E main.c  > /dev/null

real    0m0.164s
user    0m0.105s
sys 0m0.041s
folio[~/Desktop/pragma] fluffy$ time gcc -E main.c  > /dev/null

real    0m0.140s
user    0m0.097s
sys 0m0.018s
folio[~/Desktop/pragma] fluffy$ time gcc -E main.c  > /dev/null

real    0m0.193s
user    0m0.143s
sys 0m0.024s
folio[~/Desktop/pragma] fluffy$ gcc pragma.c -DPRAGMA_ONCE
folio[~/Desktop/pragma] fluffy$ ./a.out 
folio[~/Desktop/pragma] fluffy$ time gcc -E main.c  > /dev/null

real    0m0.153s
user    0m0.101s
sys 0m0.031s
folio[~/Desktop/pragma] fluffy$ time gcc -E main.c  > /dev/null

real    0m0.170s
user    0m0.109s
sys 0m0.033s
folio[~/Desktop/pragma] fluffy$ time gcc -E main.c  > /dev/null

real    0m0.155s
user    0m0.105s
sys 0m0.027s
folio[~/Desktop/pragma] fluffy$ gcc pragma.c -DPRAGMA_ONCE -DIFNDEF_GUARD
folio[~/Desktop/pragma] fluffy$ ./a.out 
folio[~/Desktop/pragma] fluffy$ time gcc -E main.c  > /dev/null

real    0m0.153s
user    0m0.101s
sys 0m0.027s
folio[~/Desktop/pragma] fluffy$ time gcc -E main.c  > /dev/null

real    0m0.181s
user    0m0.133s
sys 0m0.020s
folio[~/Desktop/pragma] fluffy$ time gcc -E main.c  > /dev/null

real    0m0.167s
user    0m0.119s
sys 0m0.021s
folio[~/Desktop/pragma] fluffy$ gcc --version
Configured with: --prefix=/Applications/Xcode.app/Contents/Developer/usr --with-gxx-include-dir=/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.12.sdk/usr/include/c++/4.2.1
Apple LLVM version 8.1.0 (clang-802.0.42)
Target: x86_64-apple-darwin17.0.0
Thread model: posix
InstalledDir: /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin

As you can see, the versions with #pragma once were indeed slightly faster to preprocess than the #ifndef-only one, but the difference was quite negligible, and would be far overshadowed by the amount of time that actually building and linking the code would take. Perhaps with a large enough codebase it might actually lead to a difference in build times of a few seconds, but between modern compilers being able to optimize #ifndef guards, the fact that OSes have good disk caches, and the increasing speeds of storage technology, it seems that the performance argument is moot, at least on a typical developer system in this day and age. Older and more exotic build environments (e.g. headers hosted on a network share, building from tape, etc.) may change the equation somewhat but in those circumstances it seems more useful to simply make a less fragile build environment in the first place.

The fact of the matter is, #ifndef is standardized with standard behavior whereas #pragma once is not, and #ifndef also handles weird filesystem and search path corner cases whereas #pragma once can get very confused by certain things, leading to incorrect behavior which the programmer has no control over. The main problem with #ifndef is programmers choosing bad names for their guards (with name collisions and so on) and even then it's quite possible for the consumer of an API to override those poor names using #undef - not a perfect solution, perhaps, but it's possible, whereas #pragma once has no recourse if the compiler is erroneously culling an #include.

Thus, even though #pragma once is demonstrably (slightly) faster, I don't agree that this in and of itself is a reason to use it over #ifndef guards.

Increasing the number of header files and changing the test to only run the preprocessor step eliminated whatever small amount of time was being added in by the compile and link process (which was trivial before and nonexistent now). As expected, the differential is about the same.

Gracioso answered 19/9, 2016 at 22:27 Comment(6)
"Negligible"? You cut your build time in half.Continuum
@LightnessRacesinOrbit I cut my build time by 0.04 seconds. Which happens to be half, on a source file that's a pathological manifestation of incredibly convoluted #include rules, that would likely never appear in real life. The point was to measure how much overhead #ifndef guards applied over #pragma once and any codebase where that's more than 0.04 seconds has bigger problems.Gracioso
Your answer provides insufficient context to tell whether the savings will remain a constant 0.04 seconds as the project grows, or will remain a constant 50% as the project grows, or some place in between. As such, it's not a terribly useful benchmark and the "negligible" conclusion is currently unsupported. I'm only mentioning it because I would be very interested in the real conclusion!Continuum
That's a good point - it only measures the speed of include guards and not the rest of the preprocessor. I figured it was obvious that the generated code was only testing that aspect given that there isn't a whole lot between the guard lines. Perhaps I could extend the generated code such that each file has a few thousand randomly generated template functions and classes, which makes for a different unrealistic synthetic test.Gracioso
Not even just the preprocessor - you're doing a full compilation & link. We just have no way of knowing from these results what the "unrelated constant overhead" is, and therefore the results don't really tell us anything of practical use. Sadly!Continuum
@LightnessRacesinOrbit I've changed the test to have more #include files and to only run the preprocessor. The time differential is, unsurprisingly, about the same (and is now a much smaller fraction).Gracioso
I
28

If you're positive that you will never use this code in a compiler that doesn't support it (Windows/VS, GCC, and Clang are examples of compilers that do support it), then you can certainly use #pragma once without worries.

You can also just use both (see example below), so that you get portability and compilation speedup on compatible systems

#pragma once
#ifndef _HEADER_H_
#define _HEADER_H_

...

#endif
Insight answered 17/7, 2009 at 15:24 Comment(16)
#pragma once is well supported over many different compilers including GCCRogers
true, but it's not ubiquitously supported. Include guards are always supported... depends on how portable you want your code to be.Insight
I really don't want both, that just makes the code ugly. As long as portability isn't an issue I think code hygiene issues are next.Delftware
Portability isn't that much of a deal even if you did care about it. If you're currently writing for Windows-only, there are likely to be other things in your code that tie you more tightly to Windows than #pragma once. And if the day should ever come you do port some of the code, it wouldn't be hard to write a Perl script that went through your headers and replaced all uses of #pragma once with an include guard based on the file name and path.Efflux
On the other hand, if part of the project is writing bits which may eventually be usable elsewhere (e.g. math library, api wrapper, etc) go for portability. You're worrying waaay too much about how your code should LOOK and not about how it should WORK.... especially at the top of a file which people have learned to ignore anyway.Esque
@onebyone: The only benefit to using #pragma once from the start is a potential performance boost. There would have to be a significant performance improvement to ever really want to move away from the "standard" way of protecting against multiple inclusions of a header. Clarity should come before performance by default - and in this case even the performance benefit is up for debate.Waldos
Identifiers starting with an underscore are reserved to the implementation; don't define them in your own code.Caras
@KeithThompson "Identifiers starting with an underscore are reserved to the implementation" -- that's too broad. Non-global identifiers may start with an underscore if not followed by a capital letter or another underscore.Fraction
@JimBalter: I was admittedly simplifying a bit -- but IMHO it's easier and wiser to follow the more general rule and never define identifiers starting with an underscore than to keep track of when you can get away with it.Caras
@KeithThompson This Q has a C++ tag and a common convention in C++ is for instance variables to start with _ so the overbroad claim could lead one to erroneously believe that these violate the standard. Anyway, I wasn't talking about practices, just the facts of what the standard says.Fraction
For what it is worth -- Oracle Solaris Studio 12.3 ("Sun Pro C") doesn't support #pragma once. I don't recall getting a warning, but I definitely got compiler errors. :(Tribade
@JimBalter Both ISO C and ISO C++ render such use undefined behavior within the standard library clauses (and in recent working draft of C++ this rule was lifted for the whole language as a "shall not be used" with "no diagnostic is required" statement, which is mentally same to UB). It is never a correct practice to use these reserved identifier unless you do know what you are doing (e.g. you're writing an implementation for the standard library).Derision
@Derision names of variables aren't "behavior", so you should cite some text from the standards for such a nonsense claim. And, as I said, starting instance variables with an underscore is a widespread practice, and the standards committees would not be so nuts as to invalidate it. And your reference to "these reserved identifier" suggests that you didn't even read what I wrote, which was about " Non-global identifiers may start with an underscore if not followed by a capital letter or another underscore", which are not and never have been reserved ... "non-global" is a big clue.Fraction
@JimBalter True, names aren't behavior, which is "external appearance or action" specified by ISO C11 3.4. However, this is nothing to do allowing use of names. See ISO C11 7.3 and ISO C++14 17.6.4.3, also the working paper of ISO C++. And "widespread" is irrelevant with "correct". Any serious projects will avoid such use unless it can get guaranteed predicable behavior by other way (e.g. extensions on the language standard like POSIX). Note, for _ + UPPERCASE, "global" is irrelevant. Further, macro names are similar to be "global".Derision
JimBalter, I was talking about the use in this answer. The statement of @KeithThompson was not precise (technically, it was wrong, but misconception based on the statement is less harmful); I'd admit I did not read about it very carefully then. But your statement of "the facts of what the standard says" in this sense is also not correct, regardless with that imprecise statement, until you recited that "not followed by a capital letter or another underscore". Also note this condition is precedent than "global". With this consensus I think we don't have disagreement any longer.Derision
" I'd admit I did not read about it very carefully then" -- indeed, and you continue in the vein. "until you recited that" -- it's what I said in the first place. "we don't have disagreement any longer" -- your disagreement was with a strawman of your own construction. "widespread" is irrelevant with "correct" -- that's the autistic view, but in the real world, standards committees (I was on X3J11 myself) take pains that widespread usages, such as _membername, remain correct. Now I've wasted more than enough time on this chitchat about a 3 year old comment, and won't engage further.Fraction
C
16

There's an related question to which I answered:

#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.

I'm adding the answer here too in case someone stumbles over this question and not the other.

Cryo answered 15/10, 2015 at 7:38 Comment(2)
@ShitalShah this is only a consideration if your build system copies files arroundCryo
Fix the #pragma once implementation, it should be using reliable checksums not sketchy filenames.Jeanettajeanette
D
15

I generally don't bother with #pragma once as my code sometimes does have to compile with something other than MSVC or GCC (compilers for embedded systems don't always have the #pragma).

So I have to use #include guards anyway. I could also use #pragma once as some answers suggest, but there doesn't seem to be much reason and it will often cause needless warnings on the compilers that don't support it.

I'm not sure what time savings the pragma might bring. I've heard that compilers generally already recognize when a header has nothing but comments outside of the guard macros and will do the #pragma once equivalent in that case (ie., never processing the file again). But I'm not sure if it's true or just a case of compilers could do this optimization.

In either case, it's just easier for me to use #include guards which will work everywhere and not worry about it further.

Dementia answered 17/7, 2009 at 18:42 Comment(1)
I'm curious which compiler doesn't support it. It appears most compilers do and I don't know of one which doesn't.Lucifer
W
9

I think the first thing you should do is check to see if this is really going to make a difference, ie. you should first test the performance. One of the searches in google threw up this.

In the results page, the columns are sligthly off for me, but it's clear that at least up to VC6 microsoft was not implementing the include guard optimisations that the other tools were using. Where the include guard was internal it took 50 times as long compared with where the include guard was external (external include guards are at least as good as #pragma). But let's consider the possible affect of this:

According to the tables presented, the time to open the include and check it is 50 times that of a #pragma equivalent. But the actual time to do so was measured at 1 microsecond per file back in 1999!

So, how many duplicate headers will a single TU have? This depends on your style, but if we say that an average TU has 100 duplicates then in 1999 we're potentially paying 100 microseconds per TU. With HDD improvements this is probably significantly lower by now, but even then with precompiled headers and correct dependency tracking the total cumulative cost of this for a project is almost certainly an insigificant part of your build time.

Now, on the flip side, as unlikely as it may be, if you ever move to a compiler that doesn't support #pragma once then consider how much time will it take to update your entire source base to have include guards rather than #pragma?

There is no reason that Microsoft could not implement an include guard optimisation in the same way that GCC and every other compiler does (actually can anybody confirm if their more recent versions implement this?). IMHO, #pragma once does very little other than limit your choice of alternative compiler.

Waldos answered 20/7, 2009 at 8:45 Comment(3)
Not to be picky, but if you're porting to a non-pragma-once supporting compiler, writing a one off tool to trawl files and replace #pragma once with conventional include guards will probably be trivial in the face of the overall porting process.Antitoxic
"actually can anybody confirm if their more recent versions implement this?" It's mentioned in the VS2015 docs that it now does implement include guard optimization. msdn.microsoft.com/en-us/library/4141z1cx.aspxDiscompose
"consider how much time will it take to update your entire source base to have include guards rather than #pragma?" It shouldn't take long. Making that easy is why I wrote guardonce.Discompose
L
4

#pragma once allows the compiler to skip the file completely when it occurs again - instead of parsing the file until it reaches the #include guards.

As such, the semantics are a little different, but they are identical if they are used they way they are intended to be used.

Combining both is probably the safest route to go, as in the worst case (a compiler flagging unknown pragmas as actual errors, not just warnings) you would just to have to remove the #pragma's themselves.

When you limit your platforms to, say "mainstream compilers on the desktop", you could safely omit the #include guards, but I feel uneasy on that, too.

OT: if you have other tips/experiences to share on speeding up builds, I'd be curious.

Lionize answered 17/7, 2009 at 15:38 Comment(2)
@Peterchen: It's wrong to state that a compiler needs to re-read the file for include guards. The first time the compiler parses the body it can record if the header had correct include guards. It can therefore skip the header if it is #included later. The key difference is that #pragma is not standard and if you ever need to use a compiler which doesn't support it then you're in a world of pain. The worse that can happen with include guards is that performance suffers very slightly.Waldos
Not really a world of pain. You could fairly easily write a script that replaced all occurences of #pragma once with include guards. The worst that can happen with include guards isn't performance, its using misspelled #ifdefs or duplicating a file, changing the contents and forgetting to update the #ifdefs.Torrell
D
1

For those who would like to use #pragma once and include guards together: If you are not using MSVC, then you won't get much optimization from #pragma once.

And you shouldn't put "#pragma once" into a header that supposed to be included multiple times with each inclusion possibly having a different effect.

Here is a detailed discussion with examples about #pragma once usage.

Dappled answered 18/1, 2013 at 3:28 Comment(0)
W
1

Atop explanation by Konrad Kleine above.

A brief summary:

  • when we use # pragma once it is much of the compiler responsibility, not to allow its inclusion more than once. Which means, after you mention the code-snippet in the file, it is no more your responsibility.

Now, compiler looks, for this code-snippet at the beginning of the file, and skips it from being included (if already included once). This definitely will reduce the compilation-time (on an average and in huge-system). However, in case of mocks/test environment, will make the test-cases implementation difficult, due to circular etc dependencies.

  • Now, when we use the #ifndef XYZ_H for the headers, it is more of the developers responsibility to maintain the dependency of headers. Which means, whenever due to some new header file, there is possibility of the circular dependency, compiler will just flag some "undefined .." error messages at compile time, and it is user to check the logical connection/flow of the entities and rectify the improper includes.

This definitely will add to the compilation time (as needs to rectified and re-run). Also, as it works on the basis of including the file, based on the "XYZ_H" defined-state, and still complains, if not able to get all the definitions.

Therefore, to avoid situations like this, we should use, as;

#pragma once
#ifndef XYZ_H
#define XYZ_H
...
#endif

i.e. the combination of both.

Wichita answered 21/9, 2015 at 11:23 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.