Why aren't include guards in c++ the default?

不羁岁月 提交于 2019-12-01 14:42:36

问题


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.


回答1:


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.




回答2:


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++.




回答3:


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.



来源:https://stackoverflow.com/questions/27260752/why-arent-include-guards-in-c-the-default

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!