Eric Fleegal's WebLog

. . . .

#pragma once

Most C++ compilers now support the non-standard #pragma once compiler directive.  This directive instructs the compiler to #include the file only once in a single compiland, and replaces the old C-style header sentinels (often called #include guards).

The central problem with preprocessor based header sentinels is that they require the user to create a unique symbol to identify each and every header file that might be #included by a single compiland.   On very large projects, this burden becomes somewhat painful.  Consider also the distinct possibility that two libraries might contain public header files with the exact same name; using the typical __FILENAME_H__ convention, its very possible to run into name collision between the two libraries.   Some project teams attempt to avoid this problem by imposing a strict sentinel naming standard, usually including a file's path as part its sentinel name.  I'm not fond of this solution because if a header file needs to be moved, as occurs when refactoring a library, it requires that the header file be edited to conform to its new location.  The #pragma once directive avoids all this nonsense entirely.

A secondary problem is one of efficiency.  The #pragma once directive allows the compiler to avoid opening and preprocessing a header file after its been seen once.  Although it is technically possible for a compiler to implement a similar mechanism when it encounters the header sentinel pattern (GCC can do this for instance), the mechanism is a bit fragile because it depends on a user following an exact coding pattern for the optimization to work correctly.  I’ve encountered code patterns in library header files that appear to be the header-sentinel pattern, but are in fact not.  Moreover, the compiler must account for the fact that preprocessor symbols can be explicitly #undef’d.  I much prefer the explicit directive because it states exactly the intention of the programmer -- "include this header only once".

Unfortunately for users of GCC, this compiler directive has been deprecated (although it’s still supported last time I checked).  It’s my personal opinion that this is yet another case of Gnu’s pervasive NIH syndrome (they got it bad), however the official reason is that the construct is not portable (which I admit is technically true).  I do not understand why the standards committee hasn’t adopted it into the ISO standard.  It’s a trivial compiler feature to implement.  Although its not an official language feature, most C/C++ compilers support it.

Published Thursday, April 17, 2008 3:02 PM by ericflee
Filed under:

Comments

 

steven said:

I generally use both. #pragma once really is a very useful thing. Pragmas are supposed to allow for implementation-specific behaviour. I don't really see a problem with its behaviour being copied in another implementation. Apparently, the creators of GCC agree because the feature was un-deprecated in GCC 3.4 (release in 2004).

The Wikipedia entry on #pragma once (http://en.wikipedia.org/wiki/Pragma_once) mentions this. And indeed a simple test shows there are no warnings when using it (gcc version 4.2.2 on my system).

April 17, 2008 7:31 PM
 

int19h said:

The reason why the GCC folks are backing out of it, and why the ISO committee will never approve it, is because it is nearly impossible to define the semantics of having "#pragma once" in a header in a proper fashion, even on a single platform. Specifically, the issue is with determining that the file being included now is one of those that have been included earlier.

Do we just compare path names? What if a file is referenced using two different relative pathnames? Do we always resolve to absolute, and then compare? Alright, then what about symbolic links and hardlinks - do we bother to check for those, or not? Note that these do not have to be on the file itself, but also on any of the directories in the path, so we'd have to check for them all. And when hardlinks are involved, on some platforms (all Unix-likes?), there's no single "primary" file name - they're all the same. Then, of course, there are network shares and UNC pathes - if, say, I share my INCLUDE folder, and then reference the same header twice, once using full UNC path, the second time using a local filesystem path, does the compiler still have to detect that? What if I'm referencing a remote server which shares the same folder under two different names? etc...

The only bulletproof way here is to compare the contents of files (or a sufficiently strong hash), but then you have to read the entire file anyway, so there isn't a huge speed benefit. On the other side, gcc at least can optimize the common header-guard pattern so that it's not any slower than #pragma once; any other compiler can do the same (and indeed, many do, though not, as I understand, MSVC).

On a side note, by far the easiest way to ensure that header guards are unique and also stand out is to use GUIDs for them.

April 18, 2008 4:50 PM
Anonymous comments are disabled

© 2009 Microsoft Corporation. All rights reserved. Terms of Use  |  Trademarks  |  Privacy Statement
Microsoft
Page view tracker