14

New to C++! So I was reading this: http://www.learncpp.com/cpp-tutorial/110-a-first-look-at-the-preprocessor/

Header guards

Because header files can include other header files, it is possible to end up in the situation where a header file gets included multiple times.

So we make preprocessor directives to avoid this. But I'm not sure - why can't the compiler just... not import the same thing twice?

Given that header guards are optional (but apparently a good practice), it almost makes me think that there are scenarios when you do want to import something twice. Although I can't think of any such scenario at all. Any ideas?

1
  • 1
    On the MS compiler there is #pragma once which tells the compiler to only include that file once. Mar 29, 2013 at 11:03

3 Answers 3

30

They can, as shown by new languages that do.

But a design decision was made all those years ago (when the C compiler was multiple independent stages) and now to maintain compatibility the pre-processor has to act in a certain way to make sure old code compiles as expected.

As C++ inherits the way it processes header files from C it maintained the same techniques. We are supporting a old design decision. But changing the way it works is too risky lots of code could potentially break. So now we have to teach new users of the language how to use include guards.

There are a couple of tricks with header files were you deliberately include it multiple times (this does actually provide a useful feature). Though if we redesigned the paradigm from scratch we could make this the non-default way to include files.

7

It wouldn't be as expressive otherwise, given that they chose to maintain compatibility with C and thus keep on with a preprocessor rather than a traditional packing system.

One thing that comes to mind for me is I had a project that was an API. I had two header files x86lib.h and x86lib_internal.h. Because internal was huge, I segregated the "public" bits to x86lib.h so that users didn't have to set aside extra time for compiling.

This introduced a funny problem with dependencies though so I ended up having a flow that went like this in x86lib_internal

  1. Set INTERNAL preprocessor define
  2. Include x86lib.h (which was smart to act a certain way when internal was defined)
  3. Do some stuff and introduce some things used in x86lib.h
  4. Set AFTER preprocessor define
  5. Include x86lib.h again (this time it'd ignore everything except for a segregated AFTER portion which depended on elements of x86lib_internal

I wouldn't say it was the best way to go about it, but it achieved what I wanted.

0

One difficulty with automatic duplicate-header exclusion is that the C standard is relatively silent on the subject of what include filenames mean. For example, suppose the main file being compiled contains directives #include "f1.h" and #include "f2.h", and the files found for those directives both contain #include "f3.h". If f1.h and f2.h are in different directories, but were found by searching include paths, then it would be unclear the #include directives within those files were intended to load the same f3.h file, or different ones.

Things get even worse if one adds in the possibilities of include files including relative paths. In some cases where header files use relative paths for nested include directives, and where one wishes avoid making any changes to supplied header files, it may be necessary to have a header file duplicated in multiple places within a project's directory structure. Even though multiple physical copies of that header file exist, they should be regarded semantically as though they are a single file.

If the #pragma once directive allowed an identifier to follow once, with the semantics that the compiler should skip the file if the identifier matches one from an earlier-encountered #pragma once directive, then the semantics would be unambiguous; a compiler which could tell that an #include directive would load the same #pragma once-tagged file as an earlier one, it could save a little time by skipping the file without opening it again, but such detection would not be semantically important since the file would be skipped whether or not the filename was recognized as a match. I'm unaware of any compilers working that way, however. Having a compiler observe whether a file matches the pattern #ifndef someIdentifier / #define someIdentifier / #endif [for that ifndef] / nothing following and treating such a thing as equivalent to the above #pragma once someIdentifier if someIdentifier remains defined, is essentially as good.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

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