Ifndef?
The One-Definition Rule: Introducing and explaining include guards.
You’ll find macros #ifndef
and #define
at the top of pretty much every C/C++ header file. However, I could not find any information about this formatting in any books or tutorials I learned from, and if they were, there was no explanation! So what are they?
For a while, I just accepted this was part of coding standards for formatting or readability and just used it myself. It was only when I took an interest in understanding compilers that I realised the purpose and importance of header guards.
Include guards are a construct used at the top of header files to stop some code from being included twice. For example, for a header file header.h
the contents of this file may look similar to the following:
#ifndef header_h_
#define header_h_
// code / contents of the file
#endif
Understanding why this is required becomes intuitive when you learn how a C/C++ compiler works. When a program is compiled into an executable the compiler will go through all the source files and convert them into one program. It does this by performing an interim step of converting the source code into one long text file ready to convert to assembly. When a source file has an #include “header.h”
the header file is opened and appended into this long text file. Once this is complete the compiler will check the files. For small projects, this does not pose any issues. However, for larger projects, certain header files may be reused multiple times. This would mean these header files are appended to the long text file multiple times and finally, this would lead to a compiler error warning that you have redefined some variables.
This is where include guards come in, the compiler will only include the header file if and if only it has not already been defined. For example, the first time a header is included the compiler will check if header_h
has been defined, if not it will define header_h
and this code between #define
and #endif
. The second time this header file is now included the compiler will check if header_h
has been defined and because it has it will skip the definition.
This is part of the One Definition Rule, which states that:
“A given class, enumeration, and template, etc., must be defined exactly once in a program.” – The C++ Programming Language, Bjarne Stroustrup.
Example
To see this in action, I have created a two simple examples for comparison. One without header guards and one with.
Without header guards
variables.hint x = 10;
int y = 20;
int x_plus_y = x + y;use_variables.h#include variables.hmain.cc#include "variables.h"
#include "use_variables.h"
// main now includes 2 copies of x and y from use_variables and variables
#include <iostream>int main() {
std::cout << x_plus_y << std::endl; return 0;
}
Running this code results in:
./variables.h:1:5: error: redefinition of 'x'
...
./variables.h:2:5: error: redefinition of 'y'
...
./variables.h:3:5: error: redefinition of 'x_plus_y'
With header guards
variables.h#ifndef variables_h_
#define variables_h_ int x = 10;
int y = 20;
int x_plus_y = x + y;#endifuse_variables.h#include variables.hmain.cc#include "variables.h"
#include "use_variables.h"
// main now does not redefine x, y and x_plus_y when including
// use_variables.h
#include <iostream>int main() {
std::cout << x_plus_y << std::endl;return 0;
}
Compiling this code results in no errors, and running the executable we get 30
, as expected.
Summary
To put into one sentence. Header guards are used to stop the compiler including the same code multiple times; this stops any variables, functions, classes etc being defined more than once.
It’s good to get into the habit of starting your header files with these header guards.