在C/ c++中包含头文件不止一次[重复]

时间:2022-08-03 15:05:20

This question already has an answer here:

这个问题已经有了答案:

Is it ever useful to include a header file more than once in C or C++?

在C或c++中多次包含头文件有用吗?

If the mechanism is never used, why would the compiler ever worry about including a file twice; if it really were useless, wouldn't it be more convenient if newer compilers made sure every header is included only once?

如果从未使用过这种机制,为什么编译器会担心包含两次文件?如果它真的没用,如果更新的编译器确保每个头都只包含一次,不是更方便吗?

Edit:

编辑:

I understand that there are standard ways of doing things like include guards and pragma once, but why should you have to specify even that? Shouldn't it be the default behavior of the compiler to include files only once?

我知道有一些标准的方法来做类似的事情,比如警卫和pragma,但是为什么你要具体说明呢?编译器不应该只包含一次文件吗?

6 个解决方案

#1


30  

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

是的,它在使用预处理器生成代码或执行Boost之类的技巧时非常有用。PP。

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:

例如,请参见X宏。基本思想是,该文件包含宏的主体,而您#定义参数,然后#包含它。这是一个做作的例子:

macro.xpp

macro.xpp

std::cout << MESSAGE;
#undef MESSAGE

file.cpp:

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.

这也允许你在参数上使用#if和朋友,这是正常宏不能做的。

#2


26  

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:

是的,包括一个头不止一次可以是有用的(尽管这是相当不同寻常的)。典型的例子是 ,它根据NDEBUG是否定义而不同地定义asssert。因此,包含它是有意义的,然后有NDEBUG的(通常是有条件的)定义,然后再包含它,并且断言(至少可能)有不同的定义: 。h>

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

assert宏根据每次 是included1。 的ndebug状态重新定义。h>

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.

1 c99,§7.2/1。

#3


14  

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>";
}

#4


4  

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

是的,只包含一次会更方便,这就是为什么要使用#pragma一次。在c++中:)

Edit:

编辑:

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

注意:#pragma once是不可移植的。您可以使用

#ifndef FILENAME_H
#define FILENAME_H

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

在你的头文件上面,如果你想要它是可移植的。

#5


1  

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:

典型的例子是一个C/ c++ enum和相应的字符串,它或多或少是这样的:

// 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

#6


-6  

#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_

如。main_win。h将_INC_MAIN_WIN_

#1


30  

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

是的,它在使用预处理器生成代码或执行Boost之类的技巧时非常有用。PP。

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:

例如,请参见X宏。基本思想是,该文件包含宏的主体,而您#定义参数,然后#包含它。这是一个做作的例子:

macro.xpp

macro.xpp

std::cout << MESSAGE;
#undef MESSAGE

file.cpp:

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.

这也允许你在参数上使用#if和朋友,这是正常宏不能做的。

#2


26  

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:

是的,包括一个头不止一次可以是有用的(尽管这是相当不同寻常的)。典型的例子是 ,它根据NDEBUG是否定义而不同地定义asssert。因此,包含它是有意义的,然后有NDEBUG的(通常是有条件的)定义,然后再包含它,并且断言(至少可能)有不同的定义: 。h>

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

assert宏根据每次 是included1。 的ndebug状态重新定义。h>

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.

1 c99,§7.2/1。

#3


14  

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>";
}

#4


4  

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

是的,只包含一次会更方便,这就是为什么要使用#pragma一次。在c++中:)

Edit:

编辑:

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

注意:#pragma once是不可移植的。您可以使用

#ifndef FILENAME_H
#define FILENAME_H

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

在你的头文件上面,如果你想要它是可移植的。

#5


1  

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:

典型的例子是一个C/ c++ enum和相应的字符串,它或多或少是这样的:

// 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

#6


-6  

#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_

如。main_win。h将_INC_MAIN_WIN_