4

Consider the following assumptions about C programming (some of which go too far, I confess):

  • Putting any variable definitions in a header file is incorrect, because each translation unit creates its own copy of the data. And if it's extern and used from more than one place, we get UB. The correct usage is to declare variables in header files and define them in the corresponding implementation files.

  • Macros are bad form and can usually be converted to variables or functions.

  • Redeclaration of functions is completely legal.

PROVIDED the above is followed, include guards become unnecessary. There is an exception for inline functions, which have to be defined in the header, but many projects do not use them.

Given all of that, why is the include guard an industry standard? Most IDEs even add them automatically upon file creation.

  • 4
    Just a few random guesses: cyclic includes from headers, performance (if a.h includes 5 headers, you don't want a.h to be expanded in full again), and of course the power to not include a header included by one you do want, by just #defineing the guard. – Sjoerd Job Postmus Nov 27 '15 at 7:34
  • 4
    Macro definitions can be repeated. Type definitions can't and are common enough in headers to warrant the systematic use of guards. Cyclic includes seem a bad idea and difficult to make work, if you have one such example which would not be better re-factorized I'm interested in it. Playing tricks by defining the guard in another place than the header seems a recipe for issues later on. – AProgrammer Nov 27 '15 at 7:45
  • Another useful thing is, when you try to cover your code with unit tests and you want to avoid including the world. You just define these guards and then you only provide definitions as required for unit testing. – thepacker Nov 28 '15 at 18:59
  • "Most IDEs even add them automatically upon file creation" - this is not quite true. IDEs have templates, and those templates have the include guards. You can normally modify the templates how you like - I normally replace those with #pragma once because that syntax is easier for me to read and is supported by every compiler I've ever used and likely will continue to be supported. – Brandin Dec 1 '15 at 10:32
10

In many (most?) non-trivial projects, header files contain typedef declarations or struct definitions. Neither of these are allowed to be repeated in a single translation unit (pre-processed source file).

As there are non-repeatable elements that are commonly placed in header files, and those elements also belong in a header file, it has become automatic for C (and C++) programmers to put include guards in their headers.

In C++, it is even more common, as inline functions are used much more and class definitions have the same restriction as struct definitions that they can't be repeated.

  • Agreed. It does not help that in C++ it is possible (and sometimes really the only way of getting an outcome) to have code in the header file. This causes a lot of confusion and the C / C++ divide is larger than many think. A mindset flip is needed to swap between C and C++ really effectively – quickly_now Nov 27 '15 at 7:59
  • It appears I overlooked quite a few things. Btw you could add the cyclic dependency issue, mentioned by AProgrammer. – Vorac Nov 27 '15 at 8:02
  • @Vorac: Include guards can break the cycle of a cyclic dependency, but they don't help in the dependency part. – Bart van Ingen Schenau Nov 27 '15 at 9:08
  • We do that with forward declarations, rights? – Vorac Nov 27 '15 at 14:13
  • @Vorac: Forward declarations indeed help in breaking dependency cycles, but that is independent of the use of headers. – Bart van Ingen Schenau Nov 27 '15 at 14:23

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.