When is it useful to include the same header several times in the same file?

I read about several inclusions of the same header in one file and found an interesting expression ( link ):

There are several tricks with header files if you consciously enable it several times (this really provides a useful feature).

I understand that these tricks are probably undesirable and get confused in real projects (especially since people take precautionary measures against many inclusions, for example include guard and #pragma once ). But still, what are these tricks? I came up with some ideas, but would like to see some factual examples (ideally, safe and verified).

My thoughts:

  • Pseudo-templates in C, where template parameters are replaced by preprocessor definitions. This can be done without inclusions, but the functions may be too large or too numerous, so creating a separate file makes sense.
  • Phased construction of a structure / class (fragment concatenation). This can help emulate inheritance in C and prevent code duplication when defining structures with common members.
  • Search tables and other compile-time data structures (again, using preprocessor definitions).
+8
c ++ c include header-files
source share
2 answers

#include "file" means taking the header file and putting all its contents in place of the #include line.

We typically used headers to identify types and to add forward declarations to source files. defining the same type twice in a file (circular inclusion always causes it) gives a compilation error, so we use #ifndef or #pragma once . (or both)

But we can also put repeating code and macros and include it several times, even in the same file. in this case, we will not use #ifndef and #pragma once . If you do this, you must be very careful and do it only if you know what you are doing.

For example: If on any operating system that invokes a specific system function (or even an ac macro like: offsetof ), a lot of warnings occur and this bothers you, and you are sure that your code is good, but you do not want to disable everything warnings that you have in the whole project or file, you just want to disable it when you call a specific function.

 //suppress the warnings: #if defined(__GNUC__) #if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6) #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wreorder" #pragma GCC diagnostic ignored "-Wunused-function" #pragma GCC diagnostic ignored "-Wunused-variable" #pragma GCC diagnostic ignored "-Wsign-compare" #pragma GCC diagnostic ignored "-Wmaybe-uninitialized" #pragma GCC diagnostic ignored "-Wsequence-point" #endif #endif // __GNUC__ //here you call the function... func(x,y,z); //unsupress: bring back the warnings to normal state #if defined(__GNUC__) #if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6) #pragma GCC diagnostic pop #endif #endif // __GNUC__ 

This will make your code look very dirty, especially if you call the function several times.

One possible solution (I do not propose that this is better ...) is to make 2 headers, one to suppress warnings and the other to cancel suppression.

In this case, your code might look like this:

 #include "suppress.h" func(x,y,z); #include "unsuppress.h" //.... more code come here //now when call it again: #include "suppress.h" func(x,y,z); #include "unsuppress.h" 
+7
source share

The "standard" example is the header <assert.h> . The effect of its inclusion depends on the value of NDEBUG :

 #include <assert.h> void func1(void) { assert(...); } #undef NDEBUG #include <assert.h> void func2(void) { assert(...); } #define NDEBUG #include <assert.h> void func3(void) { assert(...); } 

The assertion in func1() active, unless something in the compilation environment has installed NDEBUG when <assert.h> turned on. The assertion in func2() active because NDEBUG was undefined when <assert.h> was included. The statement in func3() inactive because NDEBUG was defined when <assert.h> was turned on.

Having said that, I never used this object in real life, but the standard C blessings (mandates) show behavior.

Note that this does not happen by accident; this is because the header is intentionally designed to be (re) used several times in the same TU.

+1
source share

All Articles