Include guards, or sometimes called macro guards, header guards, or file guards are a common C/C++ idiom that
allows including a header file multiple times safely.
The non-standard preprocessor directive #pragma once
is an almost equivalent alternative to this idiom.
The Problem
The preprocessor directive #include
effectively copies the named header into our source file.
If we #include
a header file more than once, this will result in redefinitions and possibly compiler errors.
Consider this example:
// point.hpp
struct point {
int x, y;
};
// main.cpp
#include "point.hpp"
#include "point.hpp"
#include <iostream>
int main() {
point p;
std::cin >> p.x >> p.y;
std::cout << p.x << ' ' << p.y << '\n';
}
This code does not compile, because we have included point.hpp
twice.
After these two includes are processed by the preprocessor, main.cpp
(ignoring comments) will be the following:
struct point {
int x, y;
};
struct point {
int x, y;
};
#include <iostream>
int main() {
point p;
std::cin >> p.x >> p.y;
std::cout << p.x << ' ' << p.y << '\n';
}
The program is ill-formed and we get a compiler error:
<source>:4:8: error: redefinition of 'point'
struct point {
^
<source>:1:8: note: previous definition is here
struct point {
^
At this point you might think: “Okay then just don’t include it twice and the problem is solved.".
But including headers multiple times is not always easy to avoid.
We could have two more header files pointmath.hpp
and pointlist.hpp
, both of which #include "point.hpp"
.
The include-tree would look as follows:
main.cpp
└─ pointmath.hpp
└─ point.hpp
└─ pointlist.hpp
└─ point.hpp
main.cpp
indirectly includes point.hpp
twice.
And this is by no means unusual.
Smaller standard library headers such as <utility>
or <new>
are included by many other headers like <vector>
, so
each source file may have many copies of <new>
.
Solution A: Include Guards
Include guards are put around the entirety of the header file:
// point.hpp
#ifndef MYPROJECT_POINT_HPP_GUARD
#define MYPROJECT_POINT_HPP_GUARD
struct point {
int x, y;
};
#endif
This idiom works by letting the preprocessor skip the entirety of the header file if MYPROJECT_POINT_HPP_GUARD
has
already been defined.
Only the first time we include the header file, will MYPROJECT_POINT_HPP_GUARD
be undefined.
We #define
this macro inside of the #ifndef
block, so all subsequent copies of the header will not be processed.
Here is how this works if we process the first two includes in main.cpp
:
#ifndef MYPROJECT_POINT_HPP_GUARD // not defined yet, so we enter the ifndef-block
#define MYPROJECT_POINT_HPP_GUARD // we define the guard
struct point {
int x, y;
};
#endif // we exit the ifndef-block
#ifndef MYPROJECT_POINT_HPP_GUARD // the guard has already been defined => skip
#define MYPROJECT_POINT_HPP_GUARD // this is not processed
struct point {
int x, y;
};
#endif // we stop skipping code here
#include <iostream>
int main() {
point p;
std::cin >> p.x >> p.y;
std::cout << p.x << ' ' << p.y << '\n';
}
After processing the #ifndef
blocks, the code will effectively look like this:
#define MYPROJECT_POINT_HPP_GUARD
struct point {
int x, y;
};
#include <iostream>
int main() {
point p;
std::cin >> p.x >> p.y;
std::cout << p.x << ' ' << p.y << '\n';
}
We could now include our point.hpp
header as many times as we want in as many headers as we want without worrying
about redefining our functions and receiving compiler errors.
Note: MYPROJECT_POINT_HPP_GUARD
is an arbitrary definition, we could name it something else too.
But the name should be long and unique so we don’t accidentally use the same guard twice.
Solution B: #pragma once
#pragma once
is a non-standard preprocessor directive which tells the preprocessor to skip the current header if it
has already been included.
The goal is to achieve the same effect as our include guards, but more concisely.
We can use it like this:
// mymath.hpp
#pragma once
struct point {
int x, y;
};
At first glance, this is much more elegant than include guards and we could just use #pragma once
in all cases.
However, as already mentioned, #pragma
directives are not part of the C or C++ standard, so the behavior is dependent
on the compiler.
One alleged advantage of #pragma once
is that
it can be faster,
since the preprocessor doesn’t need to read the entire file to find a matching #endif
for the #ifndef
directive.
The file contents can be skipped at an earlier stage.
However, these claims are hard to reproduce with modern compilers and practical examples.
It is worth noting that identifying whether a file is included multiple times is not a trival problem. In modern file systems, many symbolic links or hardlinks can lead to the same file. Usually the file contents and sometimes the timestamp are used by preprocessor to test for duplicates.
In most cases and with virtually every compiler, #pragma once
will work as intended.
But it is the subject of scepticism because it is neither fully standardized nor perfectly reliable.
An example where #pragma once
fails can be seen here:
// a.hpp
#pragma once
struct foo {};
// b.hpp
#pragma once
struct foo {};
// main.cpp
namespace a {
#include "a.hpp"
}
namespace b {
#include "b.hpp"
}
int main() {
b::foo x;
}
We get a compiler error:
main.cpp:8:3: error: foo is not a member of ´b´
b::foo x;
^~~
The contents of a.hpp
and b.hpp
are completely identical (ignoring the comments at the top).
When we attempt to #include "b.hpp"
, the preprocessor will falsely believe that b.hpp
has already been included,
because it is identical to a.hpp
.
Arguably, this is an unusual example and including inside of a namespace
is considered bad practice by many.
However, it shows that #pragma once
is not quite as reliable as include guards.
Conclusion
Include guards are a tried and tested, fully standardized, and efficient idiom which allows including a header file multiple times. Headers should be wrapped in include guards, ideally right when creating the file. Many IDEs can be configured so that they automatically add include guards when you create a new header file.
#pragma once
is a viable, but non-standard alternative for simple projects and will work most of the time, but
it can produce cryptic and very hard-to-track errors.
If you do measure a significant difference in compile times and want to use #pragma once
anyways, you can use both
include guards and #pragma once
.
Because include guards are unique for each file, the previously shown error would have been prevented:
// point.hpp
#pragma once
#ifndef MYPROJECT_POINT_HPP_GUARD
#define MYPROJECT_POINT_HPP_GUARD
struct point {
int x, y;
};
#endif