What are header guards?

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.

Code

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;
}

Code

Similarly, header files, that get included more than once,​ also give a compilation error. Take a look at the example below:

main.cpp
alphabets.h
letters.h
#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 of letters.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.

Syntax

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.

Code

Now, let’s update our example with header guards. Take a look below:

main.cpp
alphabets.h
letters.h
#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.

Copyright ©2024 Educative, Inc. All rights reserved