Is There a Case Where Including the Same Header Twice Is Actually Helpful

Is there a case where including the same header twice is actually helpful?

"Parameterized" header files can be used to simulate C++-ish-style templates in C. In such cases the header file will depend on a number of macros ("template parameters"). It will generate different code depending on the actual "value" of these macros.

So, the typical usage of such header would look as a sequence of "template parameter" macro definitions followed by the #include directive, followed by another sequence of "template parameter" macro definitions followed by the same #include, and so on.

https://stackoverflow.com/a/7186396/187690

When using this technique you will see header files without any include guards or header files with include guards that cover only a portion of the file.

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

#include "file" means take the header file and put all of its content instead of the #include line.

We usually used headers for type definitions and for adding a forward declarations to a source files. defining same type twice in a file (a circular include will always cause it) gives compilation error, therefore we use #ifndef or #pragma once. (or both)

But we also can to put a repeating code and macros and include it several times, even in the same file. in such as case, we won't use #ifndef nor #pragma once. If you do so you must be extra careful, and do it only if you know what you are doing.

For example: If in some OS calling a specific system function (or even a c macro like: offsetof) cause a bunch of warnings, and it is bothering you, and you sure your code is good, but you don't want to disable all the warnings you've got on all the project or the file, you just want to disable it when you call the 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 to look very dirty, especially if you call the function several times.

One possible solution, (I'm not suggesting it is the best one...) is to make 2 headers, in one to suppress the warnings and in the other to cancel the suppression.

In that case your code may 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"

Why is it Possible in C/C++ to Include a Header Multiple Times?

In some cases, you want to include the same header several times, for different purposes.

Are there any practical benefits for being able to include files multiple times?

Of course yes. Read also about X-macros.

For example, you are defining some enum for colors.

You could have a myenum.h header with

// file myenum.h included several times
MYENUM(red)
MYENUM(blue)
MYENUM(yellow)

(and you could imagine hundreds of other colors there, that you don't want to repeat)

then, in your main.c file (or in some guarded header file), you declare that enum using:

enum color_en {
#define MYENUM(X) X,
#include "myenum.h"
#undef MYENUM
};

and in the same main.c file, you later have a printing routine:

void print_color(enum color_en col) {
switch (col) {
#define MYENUM(X) case X: puts(#X); break;
#include "myenum.h"
#undef MYENUM
default: puts("???"); break;
}
}

Read the documentation of cpp. The #X above is stringizing X

Notice that even with modern C++, doing the same with templates is surprisingly difficult (or still impossible).

I am surprised people are not taught more about such useful tricks. Of course, you probably want to add more comments to keep your code readable.

PS. Notice that C preprocessing and its macros is profoundly (and sadly) textual - designed as string rewriting. Common Lisp and Terra and Rust macros show that other approaches are possible (they view their macro system as manipulation of ASTs).

Should I, or should I not include the same headers in different c files, which in turn are headers used in a main file?

You should include standard headers above your own headers, and you should include all the dependencies for a file in that file. If you change the includes in one of your file, it shouldn't affect any other files. Each file should maintain its own list of header dependencies.

If, in your example, dist.h includes <stdio.h>, you should not rely on this outside dist.h. If you change dist.h so that it no longer depends on <stdio.h> and remove that #include, then your program breaks.

including a header file twice in c++

Include guard prevents the content of the file from being actually seen twice by the compiler.

Include guard is basically a set of preprocessor's conditional directives at the beginning and end of a header file:

#ifndef SOME_STRING_H
#define SOME_STRING_H

//...

#endif

Now if you include the file twice then first time round macro SOME_STRING_H is not defined and hence the contents of the file is processed and seen by the compiler. However, since the first thing after #ifdef is #define, SOME_STRING_H is defined and the next time round the header file's content is not seen by the compiler.

To avoid collisions the name of the macro used in the include guard is made dependent on the name of the header file.

Multiple includes of same header file in project: C vs C++

In C,

int i;

is a tentative definition. By the virtue of inclusion, you have a tentative definition for i in two compilation units. The C standard allows to have tentative definitions in multiple compilation units, but does not mandate that implementation accept that. The custom behavior for Unix C compilers is to allow it but gcc has an option (-fno-common) to prevent it and generate an error at link time (so that you can check the code for compilers, as I think Microsoft one, which does not allow it or for platforms for which that allow better code -- I know of none but that's a rationale given by GCC documentation).

IIRC, C++ has no such allowance.

Note that you probably want a declaration and not a definition in headers. Thus for the i above it should be

extern int i;

in the header and one

int i;

at global scope in one .c file.

Including header files in C/C++ more than once

Yes, it's useful when generating code with the preprocessor, or doing tricks like Boost.PP does.

For an example, see X Macros. The basic idea is that the file contains the body of the macro and you #define the arguments and then #include it. Here's a contrived example:

macro.xpp

std::cout << MESSAGE;
#undef MESSAGE

file.cpp:

int main() {
# define MESSAGE "hello world"
# include "macro.xpp"
}

This also allows you to use #if and friends on the arguments, something that normal macros can't do.



Related Topics



Leave a reply



Submit