Internal vs External Include Guards
Asked Answered
U

2

7

I've heard that you should prefer writing internal include guards instead of external include guards.
I have searched around the internet but haven't found an answer to it.

This is a snippet of the book C++ Coding Standards by Herb & Andrei that shows an "external include guard":

Avoid using the obsolete external include guards advocated in older books:

#ifndef FOO_HJNCLUDED_ //NOT recommended
#include "foo.h"
#define FOO_HJNCLUDED_
#endif

Now, this leads to the question below:

Q: What is an internal include guard and what is an external include guard? What's the difference between the two, and why is internal include guards preferred?
I would like that the answer also provide an example.

Edit: I ended up answering my own question.

Underclassman answered 11/6, 2015 at 18:59 Comment(10)
Please edit your question with an example of each.Volva
Never heard about this terminology. Where did you read this from?Fiducial
@Fiducial C++ coding standards by Herb Sutter & Andrei Alexandrescu to mention oneUnderclassman
Include guards are usually in each header (internally). Please provide a use case for a omitting these guards using 'external' guards (I think, there is none)Cubage
@ThomasMatthews I haved edited the question and added the only explanation to the subject found in a book.Underclassman
#pragma once isn't that bad too. Even though non-standard, it is supported by all major compilers. How comes it has never been standardizedFierro
@Fiducial I've added a snippet from the book where they're talking about it.Underclassman
@AndreasDM Thanks, I learned something today, never heard about this technique before.Fiducial
@Fierro I was asking myself the same question. It seems that it is hard to come up with a reliable implementation, see e.g. #23696615 But since all major compilers seem to have figured out how to do it properly, I think it is time to standardize it.Fiducial
@Fiducial I ended up answering my own question, I did learn something new today too.Underclassman
W
6

Here's something I've seen that probably explains the comment.

Here, foo.h is defining an "internal include guard" (shortened to simply "include guard" by most people since it's the traditional way of doing it).

// foo.h
#ifndef _FOO_H__
#define _FOO_H__

// ...

#endif  // _FOO_H__

In contrast, bar.h is using foo.h's include guard outside of foo.h. We can nickname this as an "external include guard".

// bar.h
#ifndef _BAR_H__
#define _BAR_H__

#ifndef _FOO_H__
#include "foo.h"
#endif

// ...

#endif  // _BAR_H__

One (very large) project I worked on claimed that this increased compiling speed, but the claim is dubious as this seems to me like a trivial compiler optimization and I haven't seen any metrics to prove the claim. However, we did notice it was annoying to read when including multiple header files.

Wildman answered 11/6, 2015 at 19:10 Comment(10)
Which one increased compiling speed?Underclassman
Are you missing #define _FOO_H__ below #ifndef _FOO_H__ in your second example? I believe the assumption when using external header guards is that the included header file doesn't have header guards itself, and so wouldn't #define its own guard.Rozalin
I have also heard this called a "Redundant Inclusion Guard"Bontebok
But why is internal preferred?Underclassman
@AndreasDM Internal guards are good practice, otherwise, if a header gets included multiple times in a compilation unit, you'll get errors. Also, to use external guards, you need to have the internal guards already in place.Mulvihill
@AndreasDM If it's internal, then you don't have to remember to put the include guard in every single file that includes the guarded file. Say you have a widely useful header file that you include in five different places in your project. Do you want to write the include guard once, or remember to do so five times, when you'd rather be thinking about other problems?Rozalin
@Mulvihill unless you #define the guarding macro in your external guard structure.Rozalin
@AndreasDM Andre Caron's doubts about the speed difference is correct: internal include guards are such a common idiom that compilers explicitly remember whether an include file has an include guard and will not even look at the file a second time. With this optimization, there is virtually no speed difference.Shipway
@cmaster thanks for the reply, I did end up answering my own question after digging further and I think with modern compilers there is no real difference.Underclassman
@Rozalin I discovered that's partially true, external guard does not replace internal guard. I refer to my answer for more detailUnderclassman
U
3

After a good digging around, I can now answer my own question.

Internal Include Guard:

The common idiom putting "include guards" around the content of header files being included:

header.h

#ifndef HEADER_H
#define HEADER_H

// Contents of include file

#endif

Therefore, the content of the header will be processed once even though the header is #includeed multiple times.
This is known as an "internal include guard" because the guard is entirely internal to the header file.


External Include Guard:

However, there could be an issue with the above method if the compiler takes a simple approach, opening the file multiple times to check for "internal include guards" which could cause increased compile time in large projects.

header2.h

#ifndef HEADER_H
#include "header.h"
#endif

// Rest of header file goes here

The line: #ifndef HEADER_H is still defined and checked internally in header.h. But by checking it externally the compiler might avoid having to open the file at all.
It is only suggested to check externally when a header file is included from other header files.
The check is not necessary when included from a source file.


Conclusion:

  • Internal guard guarantees correctness
  • External guard may improve speed of compilation on some compilers
    • The cost involved is that of putting the check everywhere a header file is #included in another header file, and spelling the name of the guard symbol correctly. Therefore not preferred.
Underclassman answered 11/6, 2015 at 21:27 Comment(2)
You could also have edited André's answer to improve it.Tritheism
@Tritheism I agree with you, I haven't thought about that. Thanks for pointing it out.Underclassman

© 2022 - 2024 — McMap. All rights reserved.