Is it redundant to surround an #include with include guards?
Asked Answered
M

4

6

I am used to putting header guards around my objects like:

#ifndef SOMETHING_H
#define SOMETHING_H

class Something {
...
}
#endif

but I have been given code where they also do:

#ifndef SOMETHING_H
#include "something.h"
#endif

for every include. Supposedly, this is better. Why? Is this redundant with guards around the object?

Midge answered 6/11, 2013 at 0:1 Comment(4)
possible duplicate of Are redundant include guards necessary? The answer to this question is relevent to you.Radiochemical
to me it would seem that both are exactly the same, I would have thought that declaring in the header file would be better since it will always be protected, whereas outside of the header file it can be easily forgotten by a programmerElectric
@Serdalis: You are correct, this is a duplicate of that (which itself is a duplicate of #1021857. Apparently I need to work on my search abilities. Thanks.Midge
@MatthewPigram: I also thought it was a bad place to put them in the implementation but as per the other questions, it does improve compilation time.Midge
B
5

This is discussed in pretty good detail here:
http://c2.com/cgi/wiki?RedundantIncludeGuards

Here are the highlights:

  • Yes this is redundant, but for some compilers it may be faster because the compiler will avoid opening the header file if it doesn't need to.
  • "Good compilers make this idiom unnecessary. They notice the header is using the include-guard idiom (that is, that all non-comment code in the file is bracketed with the #ifndef). They store an internal table of header files and guard macros. Before opening any file they check the current value of the guard and then skip the entire file."
  • "Redundant guards have several drawbacks. They make include sections significantly harder to read. They are, well, redundant. They leak the guard name, which should be a secret implementation detail of the header. If, for example, someone renames the guard they might forget to update all the places where the guard name is assumed. Finally, they go wrong if anyone adds code outside of the guard. And of course, they are just a compile-time efficiency hack. Use only when all else fails."
Botswana answered 6/11, 2013 at 0:12 Comment(1)
That link was awesome! Thanks.Midge
D
5

The thinking behind it is the preprocessor will not need to open the header file and read the contents to determine that that header has been previously included, thus saving some time during compilation. However, most compilers these days are already smart enough to spot multiple inclusions of the same file and ignore subsequent occurrences.

Dictatorship answered 6/11, 2013 at 0:7 Comment(5)
so there is no significant gain from this then?Electric
Even if you include it several times, the include guard still do not read the code if it's already included.Duomo
@AlexandreTryHardLeblanc: I think the advantage he is getting at is that it saves the time of physically opening the header file, before it gets to reading any code.Midge
which it would seem would only add up only if not using a smart compiler, and only on large projects with many repeated header includesElectric
True enough, although I'm pretty sure most of the time the compile time saved would be negligible, I think?Duomo
B
5

This is discussed in pretty good detail here:
http://c2.com/cgi/wiki?RedundantIncludeGuards

Here are the highlights:

  • Yes this is redundant, but for some compilers it may be faster because the compiler will avoid opening the header file if it doesn't need to.
  • "Good compilers make this idiom unnecessary. They notice the header is using the include-guard idiom (that is, that all non-comment code in the file is bracketed with the #ifndef). They store an internal table of header files and guard macros. Before opening any file they check the current value of the guard and then skip the entire file."
  • "Redundant guards have several drawbacks. They make include sections significantly harder to read. They are, well, redundant. They leak the guard name, which should be a secret implementation detail of the header. If, for example, someone renames the guard they might forget to update all the places where the guard name is assumed. Finally, they go wrong if anyone adds code outside of the guard. And of course, they are just a compile-time efficiency hack. Use only when all else fails."
Botswana answered 6/11, 2013 at 0:12 Comment(1)
That link was awesome! Thanks.Midge
S
0

It's good to have this on header and class definition files, so that on compilation, if a file is referenced in a loop (a.cpp references a.h and b.cpp, and b.cpp also references a.h, a.h will not be read again) or other similar cases.

The case that worries me most about what looks like your question is that the same constant name is being defined in different files, and possibly preventing the compiler from seeing some necessary-to-see constants, classes, types, etc. as it will "believe" that the file was "already read".

Long story short, put different #ifndef constants in different files to prevent confusion.

Songster answered 6/11, 2013 at 0:12 Comment(1)
There is only one #define for any constant, it is in the .h file. everywhere else the guards are around the include statement.Midge
S
0

The purpose of doing this is to save on compile time. When the compile sees #include "something.h", it has to go out and fetch the file. If it does that ten times and the last nine all basically amount to:

#if 0
...
#endif

then you're paying the cost of finding the file and fetching it from disk nine times for no real benefit. (Technically speaking, the compiler can pull tricks to try and reduce or eliminate this cost, but that's the idea behind it.)

For small programs, the saving probably aren't very significant, and there isn't much benefit to doing it. For large programs consisting of thousands of files, it isn't uncommon for compilation to take hours, and this trick can shave off substantial amounts of time. Personally, it's not something I would do until compilation time starts becoming a real issue, and like any optimization I would look carefully at where the real costs are before running around making a bunch of changes.

Selfopinionated answered 6/11, 2013 at 0:13 Comment(2)
This would have been a good answer ~ 5 years ago. Nowadays, compilers take care of this.Reareace
@KonradRudolph You may very well be right; I don't work with enough different compilers to say how common optimizations to this are. I suspect that many programmers who use this technique picked it up years ago and have simply stuck with it without bothering to check whether it was still necessary. It's also worth pointing out that there are plenty of companies out there using compilers that are more than five years old, either because they're targeting an older platform or because upgrading didn't seem worth the costs.Selfopinionated

© 2022 - 2024 — McMap. All rights reserved.