Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Internal vs External Include Guards

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.

like image 618
Andreas DM Avatar asked Jun 11 '15 18:06

Andreas DM


People also ask

Which choice is an include guard?

In the C and C++ programming languages, an #include guard, sometimes called a macro guard, header guard or file guard, is a particular construct used to avoid the problem of double inclusion when dealing with the include directive.

Should I always use include guards?

Always write internal #include guards. Never write external #include guards.

What problem can occur when a C++ header file lacks include guards?

Without a header guard, a code file could end up with multiple (identical) copies of a given type definition, which the compiler will flag as an error.

What is the purpose of 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.


2 Answers

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.

like image 120
André Caron Avatar answered Sep 20 '22 02:09

André Caron


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.
like image 24
Andreas DM Avatar answered Sep 22 '22 02:09

Andreas DM