Search

2.12 — Header guards

The duplicate definition problem

In lesson 2.7 -- Forward declarations and definitions, we noted that a variable or function identifier can only have one definition (the one definition rule). Thus, a program that defines a variable identifier more than once will cause a compile error:

Similarly, programs that define a function more than once will also cause a compile error:

While these programs are easy to fix (remove the duplicate definition), with header files, it’s quite easy to end up in a situation where a definition in a header file gets included more than once. This can happen when a header file #includes another header file (which is common).

Consider the following academic example:

square.h:

geometry.h:

main.cpp:

This seemingly innocent looking program won’t compile! Here’s what’s happening. First, main.cpp #includes square.h, which copies the definition for function getSquareSides into main.cpp. Then main.cpp #includes geometry.h, which #includes square.h itself. This copies contents of square.h (including the definition for function getSquareSides) into geometry.h, which then gets copied into main.cpp.

Thus, after resolving all of the #includes, main.cpp ends up looking like this:

Duplicate definitions and a compile error. Each file, individually, is fine. However, because main.cpp ends up #including the content of square.h twice, we’ve run into problems. If geometry.h needs getSquareSides(), and main.cpp needs both geometry.h and square.h, how would you resolve this issue?

Header guards

The good news is that we can avoid the above problem via a mechanism called a header guard (also called an include guard). Header guards are conditional compilation directives that take the following form:

When this header is #included, the preprocessor checks whether SOME_UNIQUE_NAME_HERE has been previously defined. If this is the first time we’re including the header, SOME_UNIQUE_NAME_HERE will not have been defined. Consequently, it #defines SOME_UNIQUE_NAME_HERE and includes the contents of the file. If the header is included again into the same file, SOME_UNIQUE_NAME_HERE will already have been defined from the first time the contents of the header were included, and the contents of the header will be ignored (thanks to the #ifndef).

All of your header files should have header guards on them. SOME_UNIQUE_NAME_HERE can be any name you want, but by convention is set to the full filename of the header file, typed in all caps, using underscores for spaces or punctuation. For example, square.h would have the header guard:

square.h:

Even the standard library headers use header guards. If you were to take a look at the iostream header file from Visual Studio, you would see:

For advanced readers

In large programs, it’s possible to have two separate header files (included from different directories) that end up having the same filename (e.g. directoryA\config.h and directoryB\config.h). If only the filename is used for the include guard (e.g. CONFIG_H), these two files may end up using the same guard name. If that happens, any file that includes (directly or indirectly) both config.h files will not receive the contents of the include file to be included second. This will probably cause a compilation error.

Because of this possibility for guard name conflicts, many developers recommend using a more complex/unique name in your header guards. Some good suggestions are a naming convention of <PROJECT>_<PATH>_<FILE>_H , <FILE>_<LARGE RANDOM NUMBER>_H, or <FILE>_<CREATION DATE>_H

Updating our previous example with header guards

Let’s return to the square.h example, using the square.h with header guards. For good form, we’ll also add header guards to geometry.h.

square.h

geometry.h:

main.cpp:

After the preprocessor resolves all of the includes, this program looks like this:

main.cpp:

As you can see from the example, the second inclusion of the contents of square.h (from geometry.h) gets ignored because SQUARE_H was already defined from the first inclusion. Therefore, function getSquareSides only gets included once.

Header guards do not prevent a header from being included once into different code files

Note that the goal of header guards is to prevent a code file from receiving more than one copy of a guarded header. By design, header guards do not prevent a given header file from being included (once) into separate code files. This can also cause unexpected problems. Consider:

square.h:

square.cpp:

main.cpp:

Note that square.h is included from both main.cpp and square.cpp. This means the contents of square.h will be included once into square.cpp and once into main.cpp.

Let’s examine why this happens in more detail. When square.h is included from square.cpp, SQUARE_H is defined until the end of square.cpp. This define prevents square.h from being included into square.cpp a second time (which is the point of header guards). However, once square.cpp is finished, SQUARE_H is no longer considered defined. This means that when the preprocessor runs on main.cpp, SQUARE_H is not initially defined in main.cpp.

The end result is that both square.cpp and main.cpp get a copy of the definition of getSquareSides. This program will compile, but the linker will complain about your program having multiple definitions for identifier getSquareSides!

The best way to work around this issue is simply to put the function definition in one of the .cpp files so that the header just contains a forward declaration:

square.h:

square.cpp:

main.cpp:

Now when the program is compiled, function getSquareSides will have just one definition (via square.cpp), so the linker is happy. File main.cpp is able to call this function (even though it lives in square.cpp) because it includes square.h, which has a forward declaration for the function (the linker will connect the call to getSquareSides from main.cpp to the definition of getSquareSides in square.cpp).

Can’t we just avoid definitions in header files?

We’ve generally told you not to include function definitions in your headers. So you may be wondering why you should include header guards if they protect you from something you shouldn’t do.

There are quite a few cases we’ll show you in the future where it’s necessary to put non-function definitions in a header file. For example, C++ will let you create your own types. These user-defined types are typically defined in header files, so the definition can be propagated out to the code files that need to use them. Without a header guard, your code files can end up with multiple identical copies of these definitions, which will cause a duplicate definition compilation error.

So even though it’s not strictly necessary to have header guards at this point in the tutorial series, we’re establishing good habits now, so you don’t have to unlearn bad habits later.

#pragma once

Many compilers support a simpler, alternate form of header guards using the #pragma directive:

#pragma once serves the same purpose as header guards, and has the added benefit of being shorter and less error-prone.

However, #pragma once is not an official part of the C++ language, and not all compilers support it (although most modern compilers do).

For compatibility purposes, we recommend sticking to traditional header guards. They aren’t much more work and they’re guaranteed to be supported on all compliant compilers.

Summary

Header guards are designed to ensure that the contents of a given header file are not copied more than once into any single file, in order to prevent duplicate definitions.

Note that duplicate declarations are fine, since a declaration can be declared multiple times without incident -- but even if your header file is composed of all declarations (no definitions) it’s still a best practice to include header guards.

Note that header guards do not prevent the contents of a header file from being copied (once) into separate project files. This is a good thing, because we often need to reference the contents of a given header from different project files.

Quiz time

Question #1

Add header guards to this header file:

add.h:

Show Solution


2.13 -- How to design your first programs
Index
2.11 -- Header files

277 comments to 2.12 — Header guards

  • andfxx27

    square.h:

    square.cpp:

    main.cpp:

    I'm not sure if I have correctly format the code, but I already make sure to encapsulate them inside [code] tag.

    In the above code, is it necessary to #include "square.h" in square.cpp? or it is only to make sure that square.cpp compiles successfully (we don't have to think about the order of the function inside square.cpp, in case there are any function call to another function inside square.cpp)?

    Thank you.

  • btelfer

    I am practicing using header guards and am wondering why this does not run:

    square.h

    geometry1.h

    source.cpp

    Error:
    1>------ Build started: Project: HelloWorld, Configuration: Debug Win32 ------
    1>Source.obj : error LNK2005: _main already defined in HelloWorld.obj
    1>C:\Users\backs\source\repos\HelloWorld\Debug\HelloWorld.exe : fatal error LNK1169: one or more multiply defined symbols found
    1>Done building project "HelloWorld.vcxproj" -- FAILED.
    ========== Build: 0 succeeded, 1 failed, 0 up-to-date, 0 skipped ==========

    Thanks!

    • btelfer

      Another question: Do you need to compile everything together with ctrl + f7 rather than ctrl + f5 in Visual Studio?

    • Matteo

      1>Source.obj : error LNK2005: _main already defined in HelloWorld.obj

      Be sure your project is clean of any previous files you may have been working on.

    • keshav

      Geometry1_h is incorrect.It should be Geometry_1_h in source.cpp where you have written it.

    • 3li Mot 3alim

      The problem:
      "This program will compile, but the linker will complain about your program having multiple definitions for identifier getSquareSides!"
      The solution:
      "The best way to work around this issue is simply to put the function definition in one of the .cpp files so that the header just contains a forward declaration"
      If you want to practice this, copy the last code of the tutorial.

  • complete beginner here!

    Can someone please tell me where I can find exercises for the different concepts in c++ that'd help me make more advanced stuff in the future?

    • Viktor

      Not sure if sharing links is allowed here, but I've been toying around with edabit.com. They have a variety of challenges for different languages (C++ as well), and you can track your progress by signing up for free.

  • PINK_FLOWER

    "Let’s examine why this happens in more detail. When square.h is included from square.cpp, SQUARE_H is defined until the end of square.cpp. This define prevents square.h from being included into square.cpp a second time (which is the point of header guards). However, once square.cpp is finished, SQUARE_H is no longer considered defined. "

    What does it mean when you said "until the end of square.cpp" or "once square.cpp is finished", how a file is finished? I know we can exit from a function and finish but how about file? I understand all materials of this page well except the statements above.

    Thank you.

  • Bill

    You are not following your recommended best practice re: positioning of #include statements. In earlier lesson the best practice order is 1 - your own, 2 - 3rd party, 3 - standard. These examples position #include standard library before your own such as in main.cpp.

  • Raffaello

    I still don't understand how exactly conditional compilation directives avoid duplicate definitions. #define defines an identifier in a given file, but doesn't #ifndef defeats the purpose?
    Btw, great tutorial! I feel like I'm actually learning something and progressing!

    • Zackoric

      Defines in header files are global, so if another file defines the same header identity, the compiler recognizes that.

      • Raffaello

        I understand, but then what is the purpose of #ifndef?

        • nascardriver

          It checks if the macro is not defined, ie. if the file has not yet been included. If the file hasn't been included, #ifndef's condition is true and the file's content get included. Otherwise, the effect is the same as including an empty file.

  • Piyush Pranjal

    "If this is the first time we’ve included the header, SOME_UNIQUE_NAME_HERE will not have been defined."

    A little bit confused with this line mentioned above. I guess I am taking it in another way.

    But according to me, this line have to be changed for :

    "If this is the first time we’ve included the header, SOME_UNIQUE_NAME_HERE will be defined."
    OR
    "If this is the second time we’ve included the header, SOME_UNIQUE_NAME_HERE will not have been defined."

    Because I guess 1st time it will define the header guards but if any header already exists then the preprocessor will ignore that header by looking at the header guard on the next attempt.

    • nascardriver

      At the time of inclusion, the header guard hasn't been defined. During the inclusion, the header guard gets defined. So before the first include, SOME_UNIQUE_NAME_HERE has not been defined. After the first include (And before the second), SOME_UNIQUE_NAME_HERE has been defined. I updated the lesson to say
      "first time we're including"
      instead of
      "first time we’ve included"
      to make it clearer that the sentence is talking about the point of inclusion, not after it.

      • Piyush Pranjal

        Thanks, I got it.

      • Raghav

        I have some doubts regarding these
        first aren't header files supposed to be for declarations only
        second why preprocessor directives have extended life means it remembered definition even after first run

        • nascardriver

          > aren't header files supposed to be for declarations only
          Yes. Preprocessor directives don't count towards this rule.

          > why preprocessor directives have extended life means it remembered definition even after first run
          I'm not sure I understand your question. When you include headers, their content gets copied into the including file. So all preprocessor directives of included files are in the same file. They don't have a lifetime, only a scope. Since they're all in the same file, every preprocessor directive can be affected by previous directives.

        • Chris

          I don’t understand how, if following the practice of not defining functions in headers, header guards are commonly used. If the header only contains declarations, there is no issue. Why do we use these guards instead of changing the contents of the header to follow best practices?

  • Omran

    here is my code , it's just an overview of what i learned so far :) , i just used char and if statement , float , i actually don't know a lot about them lol :D

    MainSource.cpp

    PartnerSource.cpp

    Header.h

  • Apaulture

    In main.cpp, square.h is #included and SQUARE_H is defined. Why would square.h be included in square.cpp when the function call from main.cpp to getSquarePerimeter(arg) doesn’t take place until after getSquareSides() is called (at which point SQUARE_H is still defined)?

    main.cpp

    square.h

    square.cpp

    The only explanation I can think of is that the preprocessor resolves the directives in square.cpp and main.cpp simultaneously (not in order) before compiling.

    • nascardriver

      Directives in one source file don't affect other source files. square.cpp doesn't know what happened in main.cpp and main.cpp doesn't know what happened in square.cpp.

  • David

    Hello, thanks for these helpful lessons.

    I have no idea  why the following program can be compiled.
    In my opinion ,in source.cpp , I have used the #define ADD_H,so the contents of "add.h" will not be imported because of #ifndef. That means ,in source.cpp, the compiler does not know what the add() is. However , compiler knows what the add() is.
    Does my concept be wrong ? Thanks for replying!

    add.h

    #ifndef  ADD_H
    #define ADD_H
    int add(int x, int y);
    #endif

    add.cpp

    #include"add.h"

    int add(int x, int y)
    {
        return x + y;
    }

    source.cpp

    #include<iostream>
    #include"add.h"
    #define ADD_H

    using namespace std;

    int main()
    {
        int a = 5;
        int y = 6;
        cout<<add(a,y);

        return 0;
    }

    • nascardriver

      Please use code tags when posting code.

      A define only affects the file it is in (Reminder: An #include copies a file's content to the including file), and is only visible _after_ its definition.
      When you include "add.h" in "main.cpp", ADD_H is already defined (because "add.h" defines it and you included "add.h"). The #define in "main.cpp" has no effect.
      If you defined ADD_H before you included "add.h", you wouldn't be able to use anything from "add.h", because "add.h" sees that ADD_H is already defined, and thus does nothing.
      A #define in one .cpp file doesn't affect other .cpp files.

  • Giang from VN

    Hello, thanks for these helpful lessons. I'm using DevC (cause my laptop can't install Visual Studio, and I've not tried to installed Code::Block yet) and sometimes I get an error "Id returned 1 exit status" and don't know how to fix it. In this Header Guards lesson, I tried some code like below:

    getNum.h

    getNum.cpp

    main.cpp

    While compile "getNum.cpp", I got "undefined reference to 'WinMain@16'" and "Id returned 1 exit status" errors. While compile "main.cpp", I just got "Id returned 1 exit status", and I think the reason is the errors in "getNum.cpp" but I don't know how to fix this. Can anyone help me please

    • nascardriver

      You're trying to compile "getNum.cpp" separately from "main.cpp". Since "getNum.cpp" doesn't have a `main` function, you get a linker error.
      You need to compile all source files at the same time. I can't tell you how to do that in DevC++. DevC++ is outdated anyway, use a newer IDE and compiler (eg. Code::Blocks, so you can follow the tutorials on setting it up).

  • Chayim

    When I click on -NEXT- on the bottom it goes to page s.4.3a, and not to 2.13
    https://www.learncpp.com/cpp-tutorial/4-3a-scope-duration-and-linkage-summary/

  • Chayim

    In topic “Header Guards”:
    -When this header is #included, the preprocessor check-
    -check- missing -s- supposed to be -checks-

  • ntdong

    In this lesson, the file square.cpp has bought the header "square.h". I think it does not need because function definition of both functions ware declared in "square.h"

    int getSquareSides(); // forward declaration for getSquareSides
    int getSquarePerimeter(int sideLength); // forward declaration for getSquarePerimeter

    Therefore, the square.cpp does not need header "square.h". I run these codes in Codebock. It is ok.

  • Chayim

    Even after this solution “The best way to work around this issue is simply to put the function definition in one of the .cpp files so that the header just contains a forward declaration:”
    This does not compile, receiving this error:
    ./Playground/file0.cpp:13:10: fatal error: square.h: No such file or directory
       13 | #include "square.h"
          |          ^~~~~~~~~~
    compilation terminated.

  • Chayim

    In topic: "Header guards do not prevent a header from being included once into different code files"
    How can it compile if “int main( )” is empty and has only “return 0” ?

  • Chayim

    Should be an option to delete own comment or to edit it even after an hour.

  • l1b3rator

    This is square.h:

    #ifndef SQUARE_H
    #define SQUARE_H

    #endif

    int getSquareSides()
    {
        return 4;
    }

    This is geometry.h:

    #ifndef GEOMETRY_H
    #define GEOMETRY_H

    #endif

    #include "square.h"

    This is Project1:

    #include <iostream>
    #include "square.h"
    #include "geometry.h"

    int main()
    {
      
        return 0;
    }

    and the error that i get is:

    Error    C2084    function 'int getSquareSides(void)' already has a body    Project1    c:\c++ programs\visual studio\project1\project1\square.h    7    

    It seems like square.h gets copied twice, once from #include"square.h" and again from #include"geometry.h". I have no idea why the header guard is not working.

    Thanks for help.

      • Anderson

        Sorry nascardriver, I didn't quite understand lines 9 and line 10 of your code snippet above.

        Your comment mentioned that the #endif directive has to be at the end of the file but Im not entirely sure
        if by 'end of the file' you meant relative to the other lines of code or at the very last line(line 10) in this case.
        Please get back to me with a reply, I'll be sure to bookmark this page and come back at a later time to acknowledge your kind response.

        By the way, I love this tutorial series. I am usually not into reading tutorials myself but I've learned far more from this series than any other course I have ever taken before.
        I appreciate it nascardriver and Alex (and others who may have contributed...). Cheerio.. :)

  • Mena

    #pragma once Is pretty legal and much more useful and even faster. I look forward to see a detailed account on this important c++ feature in the next update of these great tutorials.

  • Maverick9107

    So if I am correct, the tutorial (in this chapter) doesn't explain how to resolve the issue of functions being defined more than once, if there is a need to define one in the header file, am I right ? Will the solution to this problem be explained in later chapters ?

Leave a Comment

Put all code inside code tags: [code]your code here[/code]