What kinds of header files should not be protected against multiple inclusion?
Asked Answered
T

3

15

I read the dcmtk source code, and found a comment in ofstdinc.h:

// this file is not and should not be protected against multiple inclusion

And what kinds of header files SHOULD NOT be protected against multiple inclusion?

Trinitroglycerin answered 9/5, 2015 at 12:9 Comment(1)
The ones that are trying to use a hack (multiple inclusion) to solve a problem. In your own new code it's best to try and avoid that kind of solution and always use include guards.Tobolsk
E
12

Preprocessor metaprogramming. That is, using the included file as a sort of compile-time function that performs some task. The arguments to the function are macros. For example, the file you linked has a section that looks like this:

// define INCLUDE_STACK to include "ofstack.h"
#ifdef INCLUDE_STACK
#include "dcmtk/ofstd/ofstack.h"
#endif

So if I wanted to include "ofstack.h", I would do so like this:

#define INCLUDE_STACK
#include "ofstdinc.h"
#undef INCLUDE_STACK

Now, imagine later down the line, someone wants to use this particular section of the header:

// define INCLUDE_STRING to include "ofstring.h"
#ifdef INCLUDE_STRING
#include "dcmtk/ofstd/ofstring.h"
#endif

So they do the following:

#define INCLUDE_STRING
#include "ofstdinc.h"
#undef INCLUDE_STRING

If "ofstdinc.h" had include guards, it wouldn't be included.

Engelbert answered 9/5, 2015 at 12:40 Comment(1)
In instances of such headers I've seen (typically used to paste in the bodies of enums as in the other answer), the #undefs were within the header itself. It was thus unnecessary to duplicate the #undef'ing code everywhere the header is used, and it's impossible to accidentally forget to do so.Evolute
C
12

One example are header files which expect you to define a macro. Consider a header m.h with

M( foo, "foo" )
M( bar, "bar" )
M( baz, "baz" )

This can be used in some other header like this:

#ifndef OTHER_H
#define OTHER_H

namespace other
{
    enum class my_enum
    {
#define M( k, v ) k,
#include "m.h"
#undef M
    };

    void register_my_enum();
}

#endif

and in some other file (possibly implementation):

#include "other.h"

namespace other
{
    template< typename E >
    void register_enum_string( E e, const char* s ) { ... }

    void register_my_enum()
    {
#define M( k, v ) register_enum_string( k, v );
#include "m.h"
#undef M
    }
}
Chimera answered 9/5, 2015 at 12:42 Comment(1)
FWIW, these things are sometimes known as X macros.Dejadeject
L
0

You almost always want to protect against multiple inclusion. The only time you do not want to do so is if you are doing some fancy stuff with C macros and you therefore WANT to have multiple inclusion to get the code generation you desire (don't have an example of this offhand).

Libriform answered 9/5, 2015 at 12:14 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.