Is there any situation where you wouldn't want include guards?
Asked Answered
G

6

11

I know why include guards exist, and that #pragma once is not standard and thus not supported by all compilers etc.

My question is of a different kind:

Is there any sensible reason to ever not have them? I've yet to come across a situation where theoretically, there would be any benefit of not providing include guards in a file that is meant to be included somewhere else. Does anyone have an example where there is an actual benefit of not having them?

The reason I ask - to me they seem pretty redundant, as you always use them, and that the behaviour of #pragma once could as well just be automatically applied to literally everything.

Gerdes answered 4/3, 2011 at 8:44 Comment(0)
A
11

I've seen headers that generate code depending on macros defined before their inclusion. In this case it's sometimes wanted to define those macros to one (set of) value(s), include the header, redefine the macros, and include again.
Everybody who sees such agrees that it's ugly and best avoided, but sometimes (like if the code in said headers is generated by some other means) it's the lesser evil to do that.

Other than that, I can't think of a reason.

Agrigento answered 4/3, 2011 at 8:46 Comment(6)
I've come across this particular use in the FFTW library (this is from while ago, maybe it's changed now). A number of the functions are defined so that they can be created for different underlying types: in, double, float, etc, so you can define as many types as you need and just re-include the file. However, this is a C library. In C++ of course we'd use templates...Suprematism
@the_mandrill: In C++ this is actually used in some situations where templates did not fit the problem. In particular with the boost preprocessor library to automagically generate the same code with a different number of arguments, as in boost::bind with 0, 1, 2... N arguments.Gamophyllous
@David Rodríguez: As far as I understand it, boost::bind is implemented by providing the appropriate templates for up to 9 arguments. Edit: Ok I found a place where boost does it to avoid the return x situation with functions with template arguments as return values (when the return type is void), but I've always managed to solve these with a specific template specialization for the type void. They go the route without include guards, but it's not neccessary to redefine a return macro in order to solve this problem.Gerdes
@Mephane: my bad, I did not check what library it was and mistook the one from the other. boost::signal has a signal_template.hpp header that is included from signal#.hpp, where # ranges from 0 to 10. Then signal.hpp, includes all signal#.hpp, so the signal_template.hpp is included 11 times inside signal.hppGamophyllous
I've used the multi-include construct on embedded platforms where accessing struct members via pointer to the struct was much less efficient (more than 2x the cost) of accessing global variables. Having two copies of the same piece of code which operate on separate global variables of the same struct type was cheaper than having one copy which accepted a struct pointer as an argument. Such a design would be inefficient on some other platforms, but it offered a significant space savings and even larger execution time savings versus more conventional alternative approaches.Benignant
Another example is in XFree86 (at least in the 1990s; I haven't looked more recently). Some of the DDX files were compiled for multiple bit depths by including source code with different definitions of the macros.Cornet
O
6

@sbi already talked about code generation, so let me give an example.

Say that you have an enumeration of a lot of items, and that you would like to generate a bunch of functions for each of its elements...

One solution is to use this multiple inclusion trick.

// myenumeration.td
MY_ENUMERATION_META_FUNCTION(Item1)
MY_ENUMERATION_META_FUNCTION(Item2)
MY_ENUMERATION_META_FUNCTION(Item3)
MY_ENUMERATION_META_FUNCTION(Item4)
MY_ENUMERATION_META_FUNCTION(Item5)

Then people just use it like so:

#define MY_ENUMERATION_META_FUNCTION(Item_) \
  case Item_: return #Item_;

char const* print(MyEnum i)
{
  switch(i) {
    #include "myenumeration.td"
  }

  __unreachable__("print");
  return 0; // to shut up gcc
}

#undef MY_ENUMERATION_META_FUNCTION

Whether this is nice or hackish is up to you, but clearly it is useful not to have to crawl through all the utilities functions each time a new value is added to the enum.

Oneida answered 4/3, 2011 at 9:28 Comment(4)
And if you put the #define MY_ENUMERATION_META_FUNCTION at the top myenumeration.td, you could just include the second file once and that could include the first file once. Your example looks like an arbitrary cyclic include dependency that could be avoided easily. Please correct me if I'm wrong.Gerdes
@Mephane: I don't understand how there would be a cyclic dependency given that "enumeration.td" does not include anything... Also the macro MY_ENUMERATION_META_FUNCTION is not meant to be defined in the enumeration file since it would prevent its use as a meta function, so it would kinda defeat the purpose to define it there.Oneida
Ah now I see it. The second file is not another header with code to reuse, but an actual implementation, and each implementation might define their own version of MY_ENUMERATION_META_FUNCTION. And yes, it totally feels like a hack. Whether being able to do stuff like this is an actual benefit or not would be rather subjective of course, but I see the possibility now.Gerdes
@Mephane: I must admit I am not that comfortable with it. It's heavily used within the LLVM/Clang codebase, and has the advantage of not requiring to maintain a script (in another language) to generate those functions. Proper object orientation with factories and al would work... but would be slower, and LLVM/Clang are highly optimized both in terms of memory and speed, so they don't mind use hacks as long as it benefits them.Oneida
A
4
<cassert>
<assert.h>

"The assert macro is redefined according to the current state of NDEBUG each time that <assert.h> is included."

Arthro answered 4/3, 2011 at 8:56 Comment(0)
E
0

It can be a problem if you have two headers in a project which use the same include guard, e.g. if you have two third party libraries, and they both have a header which uses an include guard symbol such as __CONSTANTS_H__, then you won't be able to successfully #include both headers in a given compilation unit. A better solution is #pragma once, but some older compilers do not support this.

Eugene answered 4/3, 2011 at 8:49 Comment(8)
What's more, #pragma once is not standard, and there's no guarantee the next version of your compiler will still support it, or support the same semantics. For me, that's a very good reason not to use it.Agrigento
@sbi: true - as is so often the case it's a trade-off between portability and issues such as the one I describe above. I guess you could always heave some really ugly boilerplate whereby you test for compiler and compiler version and then use either include guards or #pragma once accordingly, but I'm not sure I'd like to see that in every header.Eugene
Well if two include guards collide, the answer is to change one of them, not to omit...Gerdes
@Mephane: this is not an ideal solution when using third party librariesEugene
Well then you change your own colliding include guard. And if the include guards of two third party libraries collide... you could provide a wrapper with (inside its own include guard) undefines the colliding symbol and then includes the offending third party header. But this is off-topic anyway.Gerdes
@Mephane: if you re-read my answer, the example I gave was for two third party libraries, where each third party library used the same include guard for one of its header files.Eugene
The problem for #pragma once is that if you have these two files with the same include guard, and presumably the same file name, how will the compiler decide if this is two different files, or exactly the same file on two different network mounts? What do you do when it makes a mistake?Strophe
@Bo: well they don't necessarily have the same file name, and the whole point of using #pragma once is so that you don't need include guards, but yes, I can see that there could be problems with deciding whether two apparently different headers are actually the same header accessed via different paths.Eugene
S
0

Suppose you have a third party library, and you can't modify its code. Now suppose including files from this library generates compiler warnings. You would normally want to compile your own code at high warning levels, but doing so would generate a large set of warnings from using the library. You could write warning disabler/enabler headers that you could then wrap around the third party library, and they should be able to be included multiple times.

Another more sophisticated kind of use is Boost's Preprocessor iteration construct: http://www.boost.org/doc/libs/1_46_0/libs/preprocessor/doc/index.html

Senhor answered 4/3, 2011 at 8:52 Comment(2)
I don't see how not having include guards in said wrapper would make any difference. If you've already included the wrapper, the warnings are disabled for the third party header in that include already, and the second time you include the wrapper it would be caught by the include guard and not to anything at all.Gerdes
@Mephane: It's the headers containing compiler-specific warning control pragmas that go without include guards, not the warning-spattered library headers.Euromarket
S
-1

The problem with #pragma once, and the reason it is not part of the standard, is that it just doesn't always work everywhere. How does the compiler know if two files are the same file or not, if included from different paths?

Think about it, what happens if the compiler makes a mistake and fails to include a file that it should have included? What happens if it includes a file twice, that it shouldn't have? How would you fix that?

With include guards, the worst that can happen is that it takes a bit longer to compile.

Edit: Check out this thread on comp.std.c++ "#pragma once in ISO standard yet?"

http://groups.google.com/group/comp.std.c++/browse_thread/thread/c527240043c8df92

Strophe answered 4/3, 2011 at 17:47 Comment(4)
I was specifically not asking for the difference between #pragma once and #define include-guards, but for valid situations where you specifically want to include a file multiple times.Gerdes
Ok, I thought you asked why we don't have #pragma once everywhere by default. Like in the last sentence...Strophe
I was asking more about the desired effect itself; #pragma once is a means of achieving that effect, as are include-guards.Gerdes
Yes, #pragma once is fine, except when it doesn't work. :-) There is no way to make it always work, so therefore the language committee decided to not include it in the language. If it works for you, with the compiler and OS and network setup you have, fine!Strophe

© 2022 - 2024 — McMap. All rights reserved.