在C或C ++中多次包含头文件是否有用?
如果从未使用该机制,为什么编译器会担心将文件包含两次;如果真的没用,那么如果新的编译器确保每个标题只包含一次会不会更方便?
编辑:
我知道有include guards和pragma once这样的标准方式,但为什么还要指定呢?不应该只是编译器的默认行为只包含一次文件吗?
答案 0 :(得分:30)
是的,在使用预处理器生成代码或使用Boost.PP等技巧时,它很有用。
有关示例,请参阅X宏。基本思想是文件包含宏的主体,你#define
参数,然后#include
它。这是一个人为的例子:
macro.xpp
std::cout << MESSAGE;
#undef MESSAGE
file.cpp:
int main() {
# define MESSAGE "hello world"
# include "macro.xpp"
}
这也允许你在参数上使用#if
和朋友,这是普通宏无法做到的。
答案 1 :(得分:27)
是的,不止一次包含标题可以有用(尽管这很不寻常)。规范示例为<assert.h>
,根据是否定义asssert
,它会以不同方式定义NDEBUG
。因此,包含它是有意义的,然后有一个(通常是有条件的)NDEBUG定义,然后再次包含它,(至少可能)assert
的不同定义:
assert
宏根据每次NDEBUG
的当前状态重新定义<assert.h>
包括 1 。
然而,大多数标题都会出于同等的意义(即,无论它们包括多久都会产生相同的效果)。
1 C99,§7.2/ 1。
答案 2 :(得分:14)
一个典型的例子(未经测试) - 重点在于它会对枚举列表进行因子分析,以便它们在enum
和流式代码中始终显示:
// 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>";
}
答案 3 :(得分:4)
是的,只包含一次会更方便,这就是你使用#pragma一次的原因。在C ++中:)
编辑:
注意:#pragma once是不可移植的。你可以使用
#ifndef FILENAME_H
#define FILENAME_H
在您的头文件顶部,而不是您希望它是可移植的。
答案 4 :(得分:1)
当您需要一些“无聊”代码生成时,可以使用多次包含,您不希望一次又一次地手动维护。
经典的例子是C / C ++枚举和相应的字符串,或多或少看起来像这样:
// 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
答案 5 :(得分:-6)
#ifndef _INC_HEADER_
#define _INC_HEADER_
//header code
#endif
HEADER
是标题的名称
例如。 main_win.h
将为_INC_MAIN_WIN_