10

I use #pragma once (or you use include guards à la #ifndef...) basically in every header file in my c++ projects. Is this a coincidence or is it what you find for example in most open source projects (to avoid answers that rely only on personal project experience) . If so, why isn't it the other way around: If I want a header file to be included several times, I use some special pre-processor command and if not I leave the file as is.

NOhs
  • 2,780
  • 3
  • 25
  • 59
  • 9
    `#pragma once` isn't standard; `#ifndef/#define/#endif` is. – T.C. Dec 02 '14 at 23:12
  • 3
    @ T.C. Ok. But the question basically stays the same. – NOhs Dec 02 '14 at 23:15
  • You might want to take a look at `` (and ``). Two headers which would be crippled if `#pragma once` or the like was automatic. (Though it would still go against making the normal thing easy and short without making the uncommon way impossible. I mean, one could include `#pragma redo` or the like.) – Deduplicator Dec 02 '14 at 23:16
  • 4
    It probably has some strange historical reasons, nothing to do with logic. – Étienne Dec 02 '14 at 23:17
  • 4
    Well, changing it now would be a compatibility nightmare. It's probably also hard to specify correctly. (What counts as "the same file"? In a case-insensitive system, are "A.h" and "a.h" the same? How about hard or symbolic links?) – T.C. Dec 02 '14 at 23:20
  • I think C++ could use another pragma for include guards, just like `#pragma once` except you can specify a unique definition to go along with it so it knows what's up when you are using some magic in your source paths. – mukunda Dec 02 '14 at 23:27
  • 3
    Related: http://stackoverflow.com/questions/1695807/why-isnt-c-cs-pragma-once-an-iso-standard – T.C. Dec 02 '14 at 23:42
  • 1
    @mukunda `pragma` is for implementation dependent stuff. – curiousguy Dec 30 '18 at 00:58
  • the question is why guarding is not default #include behaviour – Sergei Krivonos Jun 22 '20 at 07:45

3 Answers3

8

The behavior of a C++ compiler is specified in terms of how it handles each translation unit. A translation unit is a single file after the preprocessor runs over it. The fact that we have a convention of collecting declarations in certain files and calling them "header" files means nothing to a compiler or the C++ standard.

Simply put, the standard doesn't provide for "header files" so it can't provide for automatically include guarding header files. The standard only provides for the preprocessor directive #include and the rest is merely convention. Nothing stops you from forward declaring everything and not using header files (except pity for whomever should have to maintain that code...).

So header files aren't special and there's no way to say "that's a header file, guard it", but why can't we guard everything that gets #include'd? Because #include is both more and less powerful than a module system like other languages have. #include causes the preprocessor to paste in other files, not necessarily header files. Sometimes this can be handy if you have the same using and typedef declarations in a bunch of different namespaces in different files. You could collect them in a file and #include them in a few places. You wouldn't want automatic include guards preventing you from doing that.

Using #ifndef and #define to conditionally include headers is also merely convention. The standard has no concept of "include guard". (Modern compilers however actually are aware of include guards. Recognizing include guards can allow faster compilation but it has nothing to do with correctly implementing the standard.)

Getting pedantic

The standard does liberally use the word "header", especially in reference to the C and C++ standard libraries. However, the behavior of #include is defined under § 16.2 *Source file* inclusion (emph. mine) and it does not grant any special powers to header files.

There are efforts to get a proper module system into the C++ standard.

Praxeolitic
  • 22,455
  • 16
  • 75
  • 126
  • 1
    There's "header" and there's "source file". "header"s don't need to be actual files. – T.C. Dec 02 '14 at 23:50
  • Really? Do tell. Is that because the standard allows things in <> to be provided by any implementation defined means? – Praxeolitic Dec 02 '14 at 23:51
  • 4
    Right (or unspecified, rather then implementation defined). All that's required is that writing `#include ` causes the appropriate declarations and definitions to be seen. The compiler could have special handling to recognize the standard header names and have their contents hardcoded into it, or it could fetch a chunk of AST data from an object database ... or it could just get the preprocessor to textually include a file (which is what all common implementations do in practice). – Jonathan Wakely Dec 03 '14 at 00:05
  • @JonathanWakely You got here before I could finish typing up a proper question but I found this interesting and still thought it worth sharing. http://stackoverflow.com/questions/27261508/is-a-header-necessarily-a-file – Praxeolitic Dec 03 '14 at 00:22
  • I add that there is a significant amount of code that includes the same header multiple times without guards. This is frequently done to define initialized data structures using macros. C/C++ preprocessor has always been primitive, compared to Bliss or Assembly language. – user3344003 Jan 16 '15 at 16:58
8

Because hysterical raisins.

The C++ preprocessor is almost identical to the C preprocessor, which was designed over 40 years ago. Compilers back then were much simpler. The preprocessor was even simpler, just a dumb macro processor not even a compiler. Although the C++ standard doesn't specify how it works for standard headers, conceptually #include is still the same as it was 40+ years ago: it causes the preprocessor to insert the contents of the named file into the including file.

In a simple 1970s C codebase without lots of inter-dependencies and sub-modules there may be no need for include guards. Early pre-standard C didn't use function prototypes, which is what the majority of include files are used for these days. If including a header twice caused an error you could probably re-arrange the code to prevent it being included twice.

As codebase grew and became more complex I assume the problem of accidentally including a header twice (probably indirectly, via other headers) became more common. One solution would have been to alter the preprocessor to make it smarter, but that would have required everyone to use the new preprocessor, and would have made it larger and slower. So instead a convention developed which solves the problem using existing features of the preprocessor (#define and #ifndef), not by preventing a header being included twice, but by simply making it harmless to include a header twice, because it has no effect after the first time it is included.

Over time the convention became more widely used and is now almost universal, except for the rare examples of headers which are designed to be included twice and written to work correctly that way (e.g. <assert.h>).

Later still, #pragma once was introduced by some compilers as an alternative, non-portable way to have the same effect as include guards, but by then there were many thousands of copies of various C preprocessors in use around the word and include guards had become the norm.

So the current behaviour is almost certainly due to historical reasons. Modern languages written today, for today's incredibly powerful computers, would not use something like the C preprocessor if designed from scratch. But C wasn't designed in the 21st Century. I think the include guard convention was established slowly over time, and didn't require any changes to existing software to make it work. Changing it now would break unknown quantities of C and C++ code that rely on the current behaviour and is probably not an option, as backward compatibility is important for both C and C++.

Jonathan Wakely
  • 166,810
  • 27
  • 341
  • 521
0

I'd have to agree that the main factor is historical, that said occasionally you see code that relys on them not being there. MAME is one example: it builds complex data structures (or at least last time I looked, some time ago) from a readable macro based file by including it multiple times with the macros defined differently. If include guards were automatic you'd come across code that would require a way to turn them off.

Steve
  • 1,760
  • 10
  • 18