Header guards are designed to ensure that the contents of a given header file are not copied, more than once, into any single file to prevent duplicate definitions. This is a good thing because we often need to reference the contents of a given header from different project files.
A function defined more than once returns an error. Take a look at the example below:
#include <iostream>int foo() // this is a definition for function foo{return 5;}int foo() // compile error: duplicate definition{return 5;}int main(){std::cout << foo();return 0;}
Similarly, header files, that get included more than once, also give a compilation error. Take a look at the example below:
#include "letters.h"#include "alphabets.h"#include <iostream>int main(){return 0;}
Here’s what’s happening: First, main.cpp
includes letters.h
, which copies the definition for function getNumLetters
into main.cpp
. Then, main.cpp
#includes
alphabets.h
, which includes letters.h
itself. This copies contents of letters.h
(including the definition for function getNumLetters
) into alphabets.h
, which then get copied into main.cpp
.
Individually, each file is fine. However, since
main.cpp
ends up including the content ofletters.h
twice, we’ve run into problems.
If alphabets.h
needs getNumLetters()
, and main.cpp
needs both alphabets.h
and letters.h
, how would you resolve this issue? This is where header guards come in.
Header guards are conditional compilation directives that take the following form:
#ifndef BLAH#define BLAH// your declarations (and certain types of definitions) here#endif
When this header is included, the preprocessor checks whether BLAH
has been previously defined. If this is the first time the header is included, BLAH
will not have been defined. Consequently, it defines BLAH
and includes the contents of the file. If the header is included again into the same file, BLAH
will already have been defined and thus, the contents of the header will be ignored (thanks to the #ifndef
).
BLAH
can be any name you want, but it should be the full filename of the header file, in all caps, with underscores for spaces and punctuation.
Now, let’s update our example with header guards. Take a look below:
#include "letters.h"#include "alphabets.h"#include <iostream>int main(){return 0;}
The second inclusion of the contents of letters.h
(from alphabets.h
) gets ignored because LETTERS_H
was already defined from the first inclusion. Therefore, function getNumLetters
only gets included once, and the program compiles successfully.