venkysmarty
venkysmarty

Reputation: 11431

about include header file with guards

I am reading a book on Applied C++.

Include guards will prevent a header file from being included more than once during the compilation of source file. Your symbol names should be unique, and we recommend choosing the name based on the name of the file. For example, our file, cache.h contains this include guard.

#ifndef _cache_h_
 #define _cache_h_
 ...
 #endif // _cache_h_

Lakos describes using redundant include guards to speed up compilation. See [Lakos96]. For large projects, it takes times to open each file, only to find that the include guard symbol is already defined (i.e., the file has already been included). The effects on compilation time can be dramatic, and Lakos shows a possible 20x increase in compilation times when only standard include guards are used.

[Lakos96]: LargeScale C++ software design.

I don't have Lakos96 reference book to refer concept so asking help here.

My questions on above text is

  1. What does author mean by " For large projects, it takes times to open each file, only to find that the include guard symbol is already defined" ?

  2. What does author mean by "when standard include guards are used" ?

Thanks for your time and help.

Upvotes: 6

Views: 2748

Answers (6)

Stefano Falasca
Stefano Falasca

Reputation: 9097

From C++ Coding Standards (Sutter, Alexandrescu)

Many modern C++ compilers recognize header guards automatically (see Item 24) and don't even open the same header twice. Some also offer precompiled headers, which help to ensure that often-used, seldom-changed headers will not be parsed often

So, I would consider those suggestions outdated (unless you are still using some very dated compiler).

As for your questions:

  1. it means: opening a file which is not needed (since it has been already included; which you will know because the include guard is already defined) is costy; and this might be an issue if you do it a lot of times (which can happen if you have hundreds of files in your project).
  2. as opposed to using non-redundant compile guards.

What is a redundant compile guard?

A naive compiler will reload the file every time it's included. To avoid that, put RedundantIncludeGuards around the include: header.h

 #ifndef HEADER_H_
  #define HEADER_H_
  // declarations
  #endif

foo.c

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

read more here. Your reference claims that by doing so you can be as much as 20% faster during compilation than you would be if foo.c were only doing

 #include "header.h"

Upvotes: 8

SteveLove
SteveLove

Reputation: 3207

In a large project, there may be many headers - perhaps 100s or even 1000s of files. In the normal case, where include guards are inside each header, the compiler has to check (but see below) the contents of the file to see if it's already been included.

These guards, inside the header, are "standard".

Lakos recommends (for large projects) putting the guards around the #include directive, meaning the header won't even need to be opened if it's already been included.

As far as I know, however, all modern C++ compilers support the #pragma once directive, which coupled with pre-compiled headers means the problem is no longer an issue in most cases.

Upvotes: 1

Jan Spurny
Jan Spurny

Reputation: 5528

  1. in larger projects with more people, there may be, for example, one module dealing with time transformation and it's author could chose to use TIME as a guard. Then you'll have another one, dealing with precise timing and it's author, unaware of the first one, may choose TIME too. Now you have a conflict. If they used TIME_TRANSFORMATION and PRECISE_TIMING_MODULE, they'll be ok

  2. Don't know. I would guess it coud mean "when you do it every time, consistently, it becomes your coding standard".

Upvotes: 0

doctorlove
doctorlove

Reputation: 19232

Lakos' book is old. It may have been true once, but you should time things on your machine. Many people now disagree with him, e.g. http://www.allankelly.net/static/writing/overload/IncludeFiles/AnExchangeWithHerbSutter.pdf or http://c2.com/cgi/wiki?RedundantIncludeGuards or http://gamearchitect.net/Articles/ExperimentsWithIncludes.html

Herb Sutter, C++ guru and current chair of the ISO C++ standards committee, argues against external include guards:

"Incidentally, I strongly disagree with Lakos' external include guards on two grounds:

  1. There's no benefit on most compilers. I admit that I haven't done measurements, as Lakos seems to have done back then, but as far as I know today's compilers already have smarts to avoid the build time reread overhead--even MSVC does this optimization (although it requires you to say "#pragma once"), and it's the weakest compiler in many ways.

  2. External include guards violate encapsulation because they require many/all callers to know about the internals of the header -- in particular, the special #define name used as a guard. They're also fragile--what if you get the name wrong? what if the name changes?"

Upvotes: 6

Mats Petersson
Mats Petersson

Reputation: 129344

I think what it refers to is to replicate the include guard outside of the header file, e.g.

#ifndef _cache_h_
#include <cache.h>
#endif

However, if you do this, you'll have to consider that header guards are sometimes changing within a file. And you certainly won't see a 20x improvement in a modern system - unless all your files are on a very remote network drive, possibly - but then you'll have a much better improvement from copying the project files to your local drive!

There was a similar question a while back, regarding "including redundant files" (referring to including header files multiple times), and I built a smallish system with 30 source files, which included <iostream> "unnecessarily", and the overall difference in compile time was 0.3% between including and not including <iostream>. I believe this finding shows the improvement in GCC that "automatically recognises files that produce nothing outside of include guards".

Upvotes: 1

rodrigo
rodrigo

Reputation: 98348

I don't know what Lakos96 says, but I'm going to guess anyway...

A standard include guard is like:

foo.h

#ifndef FOO_H_INCLUDED
#define FOO_H_INCLUDED
....
#endif

A redundant include guard is using the macro when including the file:

bar.c

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

That way the second time the foo.h file is included, the compiler will not even search for it in the disk. Hence the speedup: imagine a large project, one single compilation unit may include foo.h 100 times, but only the first one will be parsed. The other 99 times it will be searched for, opened, tokenized, discarded by the pre-compiler and closed.

But note that that was in 1996. Today, GCC, to give a well known example, has specific optimizations that recognize the include guard pattern and makes the redundant include guard, well..., redundant.

Upvotes: 7

Related Questions