Good practice concerning header guards (C++)

Started by
7 comments, last by styrbjorn 12 years, 1 month ago
I am learning C++, and I just ran into a section about header guards and how to split programs into multiple files.

Let's say that I have a simple program that doubles a number entered by the user, and outputs the result on the screen.

Here is my main.cpp

#include "double.h"
int main()
{
int nUserNumber=GetNumber();
int nDoubleNumber=DoubleNumber(nUserNumber);
PrintResult(nDoubleNumber);
return 0;
}


Here is double.h


#ifndef _IOSTREAM_
#define _IOSTREAM_
#include <iostream>
#endif

#ifndef GETNUMBER
#define GETNUMBER

int GetNumber();

#endif

#ifndef DOUBLENUMBER
#define DOUBLENUMBER

int DoubleNumber(int nUserNumber);

#endif

#ifndef PRINTRESULT
#define PRINTRESULT

int PrintResult(int nDoubleNumber);

#endif



Here is getnumber.cpp


#include "double.h"
int GetNumber()
{
int nUserNumber=0;
std::cout<<"Please enter a number: ";
std::cin>>nUserNumber;

return nUserNumber;
}


Here is doublenumber.cpp:


#include "double.h"
int DoubleNumber(int nUserNumber)
{
return nUserNumber*2;
}


And lastly, printresult.cpp:


#include "double.h"
void PrintResult(int nDoubleNumber)
{
std::cout<<nDoubleNumber;
}


The reason I add iostream to my header file instead of main.cpp is that GetNumber and PrintResult needs it for cin and cout. My question is whether this is good practice or not, or something that I should solve in a different way? The program runs without any errors, but I am concerned about not picking up any bad habits along the way :)
Advertisement

  • Be wary (i.e. don't do it) of using identifiers which start with an underscore and a capital letter (_Likethis) - they're reserved for the implementation, so e.g. the standard library can feel free to use helpers without conflicting with identifiers in the user's code. Similar story for anything starting with a double underscore (__Likethis but also __likethis).
  • You don't want to include the header if you can avoid it - instead, include it in the source file that needs it (getnumber.cpp, doublenumber.cpp, printresult.cpp). This way you don't drag unnecessary things into files that don't need them, cluttering namespaces and perhaps increasing compile times.
  • You want to protect the header as a whole, not the individual declarations: #ifndef DOUBLE_H
    #define DOUBLE_H

    int GetNumber();
    int DoubleNumber(int nUserNumber);
    int PrintResult(int nDoubleNumber);

    #endif

  • I wouldn't generally restrict myself to a single function per source file. It can actually make things harder to read. I try to keep the content of both headers and source files grouped into what I see as logical clumps of code, with no hard-and-fast rule. So I'd have at least GetNumber and PrintResult in the same file, for example.
[TheUnbeliever]
Thanks a lot for the quick reply. The things you write make sense to me, but I am wondering where I am supposed to include iostream. If I include iostream in my main.cpp, my other cpp files does not seem to find it, but if I include it in every .cpp-file (that uses cout or cin) in the project it seems logical to me that I would end up with having multiple "copies" of iostream. Is this the case, or am I missing something?

Here is the program again, after the alterations, and it still works:

main.cpp:

#include "double.h"
int main()
{
int nUserNumber=GetNumber();
int nDoubleNumber=DoubleNumber(nUserNumber);
PrintResult(nDoubleNumber);

return 0;
}


double.h:

#ifndef DOUBLE_H
#define DOUBLE_H

int GetNumber();

int DoubleNumber(int nUserNumber);

void PrintResult(int nResult);

#endif


getnumber.cpp:

#include <iostream>

int GetNumber()
{
int nNumber=0;
std::cout<<"Please enter a number: ";
std::cin>>nNumber;

return nNumber;
}

void PrintResult(int nDoubleNumber)
{
std::cout<<nDoubleNumber;
}



doublenumber.cpp


int DoubleNumber(int nValue1)
{
return nValue1*2;
}



In this case, iostream is only included once, but in the previous version it was needed in two different files (getnumber.cpp and printresult.cpp). Should I just put #include <iostream> in each file in that case?
Thanks a lot for the quick reply. The things you write make sense to me, but I am wondering where I am supposed to include iostream. If I include iostream in my main.cpp, my other cpp files does not seem to find it, but if I include it in every .cpp-file (that uses cout or cin) in the project it seems logical to me that I would end up with having multiple "copies" of iostream. Is this the case, or am I missing something?


The reason that including iostream in main.cpp isn't enough is that each source file is compiled separately. It's worth reading up on the C++ compilation model, but basically each source file is individually compiled to an object file. Each object file can refer to symbols which are defined in another. To compile, you just need a declaration - it's enough to say "there's a function called foo with the signature bar", but to actually execute the program, you obviously need the actual definition. So the linker takes these object files, resolves all the references to symbols including across files, and produces a single, coherent executable.

If you include a file, that file is substituted (copied-and-pasted) into the file containing the #include directive. So if you include iostream in main, the other source files know literally nothing about it when they're compiled. So iostream must be somewhere in a chain of includes from the source file that requires it, but ideally as near the bottom as possible, so that it's only visible to stuff that really needs it. In your example, the 'as near the bottom as possible' would be directly in each of the two source files, yes.
[TheUnbeliever]


  • Be wary (i.e. don't do it) of using identifiers which start with an underscore and a capital letter (_Likethis) - they're reserved for the implementation, so e.g. the standard library can feel free to use helpers without conflicting with identifiers in the user's code. Similar story for anything starting with a double underscore (__Likethis but also __likethis).
  • You don't want to include the header if you can avoid it - instead, include it in the source file that needs it (getnumber.cpp, doublenumber.cpp, printresult.cpp). This way you don't drag unnecessary things into files that don't need them, cluttering namespaces and perhaps increasing compile times.
  • You want to protect the header as a whole, not the individual declarations: #ifndef DOUBLE_H
    #define DOUBLE_H

    int GetNumber();
    int DoubleNumber(int nUserNumber);
    int PrintResult(int nDoubleNumber);

    #endif

  • I wouldn't generally restrict myself to a single function per source file. It can actually make things harder to read. I try to keep the content of both headers and source files grouped into what I see as logical clumps of code, with no hard-and-fast rule. So I'd have at least GetNumber and PrintResult in the same file, for example.



If you are targeting a compiler that supports "#pragma once" and never have to be able to compile in one that doesn't you can use that directive instead of the include guard. Be aware that not all compilers support this directive as it is non-standard.
http://en.wikipedia....iki/Pragma_once

A way arround you having to include all common headers everywhere is making one header that just includes the ones you need everywhere and only include that one at the top of your cpps. Precompiled headers might help as well with compile times in bigger projects.

Worked on titles: CMR:DiRT2, DiRT 3, DiRT: Showdown, GRID 2, theHunter, theHunter: Primal, Mad Max, Watch Dogs: Legion

To be honest, I don't really understand why people continue to mess around with include guards in this day and age.

#pragma once


Done.

Granted, pragma's aren't by nature portable, but I can't think of a C++ compiler in the last decade that didn't properly support #pragma once. Using pragma once removes the chance of a name collision and simply make life easier.


That said, especially in game sources, I almost never see it used, seems silly to me.

[quote name='TheUnbeliever' timestamp='1330600605' post='4918132']

  • Be wary (i.e. don't do it) of using identifiers which start with an underscore and a capital letter (_Likethis) - they're reserved for the implementation, so e.g. the standard library can feel free to use helpers without conflicting with identifiers in the user's code. Similar story for anything starting with a double underscore (__Likethis but also __likethis).
  • You don't want to include the header if you can avoid it - instead, include it in the source file that needs it (getnumber.cpp, doublenumber.cpp, printresult.cpp). This way you don't drag unnecessary things into files that don't need them, cluttering namespaces and perhaps increasing compile times.
  • You want to protect the header as a whole, not the individual declarations: #ifndef DOUBLE_H
    #define DOUBLE_H

    int GetNumber();
    int DoubleNumber(int nUserNumber);
    int PrintResult(int nDoubleNumber);

    #endif

  • I wouldn't generally restrict myself to a single function per source file. It can actually make things harder to read. I try to keep the content of both headers and source files grouped into what I see as logical clumps of code, with no hard-and-fast rule. So I'd have at least GetNumber and PrintResult in the same file, for example.



If you are targeting a compiler that supports "#pragma once" and never have to be able to compile in one that doesn't you can use that directive instead of the include guard. Be aware that not all compilers support this directive as it is non-standard.
http://en.wikipedia....iki/Pragma_once

A way arround you having to include all common headers everywhere is making one header that just includes the ones you need everywhere and only include that one at the top of your cpps. Precompiled headers might help as well with compile times in bigger projects.
[/quote]


What ironic timing. :)


Frankly if you are still using LCC-Win32 from 2004, or GCC from 1998 ( the two compilers not supporting #pragma once correctly ), you have much greater problems to deal with! :D

Granted, pragma's aren't by nature portable, but I can't think of a C++ compiler in the last decade that didn't properly support #pragma once.


The Wikipedia page on #pragma once mentions some bugs in the support from a couple of compilers, and gcc didn't handle symbolic links correctly until gcc-3.4 (2004). But nowadays I think I have to agree with you that there is no reason not to use it.
Thanks again for the constructive input. I think I am on the right path now. While pragma seems like a interesting directive, but I want to keep as close to the turotial I am following as possible, even if it's a bit boring. Taking shortcuts has been my downfall so many times before (e.g. downloading a game programming API before learning about classes and such - I lose interest when I don't know what stuff does what :) ).

I'll keep working towards a first simple game now, but I need to cover a few more concepts first.

This topic is closed to new replies.

Advertisement