不止一次在C / C ++中包含头文件

时间:2012-06-04 07:03:19

标签: c++ c header-files

在C或C ++中多次包含头文件是否有用?

如果从未使用该机制,为什么编译器会担心将文件包含两次;如果真的没用,那么如果新的编译器确保每个标题只包含一次会不会更方便?

编辑:

我知道有include guardspragma once这样的标准方式,但为什么还要指定呢?不应该只是编译器的默认行为只包含一次文件吗?

6 个答案:

答案 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_