It’s Okay to Use #pragma once
In C and C++, there is a non-standard preprocessor directive called #pragma once
.
This directive prevents the same file (usually a header file) from being included multiple times.
Although #pragma once
is non-standard, it is widely supported across different environments, so it’s generally fine to use it.
In fact, nowadays, unless there’s a special reason not to, I believe it should be actively used.
The standard include guard would look like this:
#ifndef THIS_HEADER_INCLUDED
#define THIS_HEADER_INCLUDED
#endif // THIS_HEADER_INCLUDED
When I first started learning, I was taught to “use this standard include guard instead of #pragma once
to improve portability.”
However, with the standard include guard, if the symbol used unintentionally overlaps with another header file, it could prevent one of the header files from being loaded, which may lead to tricky bugs and errors.
I’ve encountered this type of error a few times, for example, when I copied a sample header file to create a new header and forgot to update the symbol.
Additionally, there are also common mistakes such as mistakenly using #ifdef instead of #ifndef, which can cause the header file to never be read, or making a typographical error in the symbols on the first and second lines, resulting in the include guard not functioning at all.
Since #pragma once
does not define any symbols, this kind of error fundamentally cannot occur, which is an advantage of #pragma once.
Also, while the standard include guards themselves are not problematic, it is also an issue that symbols like the following are commonly used:
#ifndef __THIS_HEADER_INCLUDED__
#define __THIS_HEADER_INCLUDED__
#endif // __THIS_HEADER_INCLUDED__
The symbol __THIS_HEADER_INCLUDED__
is actually a reserved identifier.
According to the C++ standard (ISO/IEC 14882:2023), in section $5.10 Identifiers, the following is stated about reserved identifiers:
In addition, some identifiers appearing as a token or preprocessing-token are reserved for use by C++ implementations and shall not be used otherwise; no diagnostic is required.
- Each identifier that contains a double underscore __ or begins with an underscore followed by an uppercase letter is reserved to the implementation for any use.
- Each identifier that begins with an underscore is reserved to the implementation for use as a name in the global namespace.
Similarly, the C standard (ISO/IEC 9899:2024) in section $6.4.2 Identifiers states:
Some identifiers are reserved.
- All identifiers that begin with a double underscore (__) or begin with an underscore (_) followed by an uppercase letter are reserved for any use, except those identifiers which are lexically identical to keywords.
- All identifiers that begin with an underscore are reserved for use as identifiers with file scope in both the ordinary and tag name spaces.
In both cases, identifiers beginning with a double underscore are reserved, so __THIS_HEADER_INCLUDED__
qualifies as a reserved identifier under this rule.
Another commonly seen symbol is _THIS_HEADER_INCLUDED_
, but this is also problematic, as identifiers beginning with an underscore followed by an uppercase letter are reserved.
There are people who insist on not using the non-standard #pragma once
, yet write include guards with these non-standard-compliant identifiers, which suggests that this practice has deep roots.
#pragma once
is not without its drawbacks.
Since it is not standardized, it depends on compiler-specific behavior.
There is a potential for tricky errors if, for example, symbolic links are used in the source code, as the method for determining file identity may vary by compiler.
However, in my experience, I’ve never encountered issues caused by this, while I have run into problems with symbol collisions using standard include guards several times.
Unless you’re working on a large codebase that uses symbolic links, hard links, or network file systems, and also needs to support multiple compilers, I generally recommend using #pragma once
for its advantages.