Including header files in C/C++ more than once [duplicate]

我与影子孤独终老i 提交于 2019-11-27 19:58:20

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.

Yes, including a header more than once can be useful (though it is fairly unusual). The canonical example is <assert.h>, which defines asssert differently depending on whether NDEBUG is defined or not. As such, it can make sense to include it, then have a (usually conditional) definition of NDEBUG, followed by including it again, with (at least potentially) different definitions of assert:

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

Most headers, however, go to some pains to be idempotent (i.e., to have the same effects no matter how often they're included).


1C99, §7.2/1.

A typical example (untested) - point being that it factors a list of enumerations so they appear consistently in an enum and in streaming code:

// states.h
X(Uninitialised)
X(Initialised)
X(Running)
X(Complete)
X(Shutdown)

// app.c++
#if defined(X)
# error X is already defined
#endif

enum States {
    #define X(TAG) TAG,
    #include "states.h"
    #undef X
    Extra_So_Trailing_Comma_Ignored
};

std::ostream& operator<<(std::ostream& os, const States& state)
{
    #define X(TAG) if (state == TAG) return os << #TAG;
    #include "states.h"
    #undef X
    return os << "<Invalid-State>";
}

Yes it would be more convenient only to include it once and that is why you use #pragma once . in C++ :)

Edit:

Note: #pragma once is non-portable. You can use

#ifndef FILENAME_H
#define FILENAME_H

in top of your header files instead if you want it to be portable.

Multiple inclusion can be used whenever you need some "boring" code generation that you don't want to maintain by hand, again and again.

The classic example would be a C/C++ enum and the corresponding strings, which more or less looks like this:

// MYENUM_VALUES.H
MYENUMVALUE(a)
MYENUMVALUE(b)
MYENUMVALUE(c)
MYENUMVALUE(d)

// MYENUM.H
#define MYENUMVALUE(x) x,
enum MyEnum
{
#include "MYENUM_VALUES.H"
}
#undef MYENUMVALUE

// MYENUMTOSTRING.C
#define MYENUMVALUE(x) case x : return #x;

const char * MyEnumToString(MyEnum val)
{
    switch (val)
    {
    #include "MYENUM_VALUES.H"
    default return "unknown";
    }
} 
#undef MYENUMVALUE
#ifndef _INC_HEADER_
#define _INC_HEADER_

//header code

#endif

Where HEADER is the header's name

eg. main_win.h will be _INC_MAIN_WIN_

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!