In C and C++ there exists the concept of include guards (header guards) to prevent that a header file (or rather the content of such file) is included more than once, because that could cause errors and strange behavior due to redeclarations or name collisions1.
Current idioms
Two approaches that are often used to circumvent multiple inclusions:
-
Using the preprocessor directive #pragma once, but that is non-standard and comes with its own caveats.
-
Using a more wordy, but standard-conformant set of preprocessor directives that use an unique identifier (usually the filename), for example:
#ifndef UTILITES_HPP #define UTILITES_HPP // ... #endif
One problem with that: When your project grows (or if you use it in a project with other dependencies and include many other header files), the probability of a name clash can also increase, especially for common names, such as “utilities”.
The next logical step is to extend the identifier, to make it more rare, for example by adding a variant of the (full) path or namespace:
#ifndef PROJECT_X_MODULE_A_UTILITIES_HPP
#define PROJECT_X_MODULE_A_UTILITIES_HPP
// ...
#endif
Growing apart
So far, so good; but I personally get the structure or design of my file hierarchy or namespaces seldom perfectly right on the first try – so I refactor.
And sometimes frequently and/or radical, especially when a project is in its infancy, or is only used by myself (as far as I’m aware). And that may lead to a mismatch of how the identifiers are composed and how the actual namespace (and/or filepath) actually look like after a refactor session; for example:
- Same define-identifier in the source code (
#define PROJECT_X_MODULE_A_UTILITIES_HPP
) – but other properties maybe have changed: - New namespace after the change:
namespace BetterProjectName::ModuleY::Tools { /*...*/ }
- New filepath after the change:
.../BetterProjectName/ModuleY/tools.hpp
\
(Maybe there are external tools and checkers which could scan a project to find such discrepancies, but I don’t know any; and also, that would again lead to an additional dependency on an extra tool…)
On the positive side, technically it doesn’t matter: The include guard identifier is an implementation detail and usually only used internally (in the file; by the preprocessor/compiler), so no other parts of the project should use or even know about it.
My adaptation and customization
But it bothers me personally when things grow apart in this manner; so, what to do instead?
Something that I’ve seen (being recommended) quite often is to use a GUID/UUID. On the one hand, that sounds sensible; on the other hand, the unadulterated hexadecimal gibberish looks more like machine-generated code (which it is…) than a proper decision of a developer.
So, I decided for now to strike a balance between these two extremes: Some text fragements that hint to the project and/or component, and a part of random alphanumeric characters.
Of course, that makes generating/typing such an include guard by hand tedious. And for that reason, I wrote a little helper function in Powershell to generate a code snippet: It produces strings like the pair shown below; the custom text and the order of the parts can be specified by the parameters, and the script also ensures that the string conforms to the usual requirements (all uppercase, spaces and special characters converted to underscores, no leading number) and even automatically copies it to the clipboard.
Order: <StandardText>_<CustomText>_<GUID> | Order: <CustomText>_<StandardText>_<GUID> |
---|---|
#ifndef INCLUDE_GUARD_PROJECT_X_DCB2080F_F250_4A8C_A988_3C6659C7A511 #define INCLUDE_GUARD_PROJECT_X_DCB2080F_F250_4A8C_A988_3C6659C7A511 |
#ifndef PROJECT_X_INCLUDE_GUARD_DCB2080F_F250_4A8C_A988_3C6659C7A511 #define PROJECT_X_INCLUDE_GUARD_DCB2080F_F250_4A8C_A988_3C6659C7A511 |
-
In the future, all this may be no longer neccessary, thanks to C++20’s modules, but for now, that is too new, not implemented fully by all compilers and lacks proper tooling support (e.g. in CMake). ↩︎
Film & Television (54)
How To (63)
Journal (17)
Miscellaneous (4)
News & Announcements (21)
On Software (12)
Projects (26)