48

C または C++ でヘッダー ファイルを複数回インクルードすると便利ですか?

このメカニズムがまったく使用されていない場合、コンパイラはファイルを 2 回インクルードすることを心配する必要があります。もしそれが本当に役に立たないのなら、新しいコンパイラがすべてのヘッダーが一度だけ含まれることを確認した方が便利ではないでしょうか?

編集:

include Guardspragma onceなどの標準的な方法があることは理解していますが、それを指定する必要があるのはなぜですか? ファイルを一度だけインクルードするのは、コンパイラのデフォルトの動作であるべきではありませんか?

4

6 に答える 6

30

はい、プリプロセッサでコードを生成したり、Boost.PP のようなトリックを実行したりするときに役立ちます。

例については、X マクロを参照してください。基本的な考え方は、ファイルにはマクロの本体と#define引数、そして#includeそれが含まれているということです。これは不自然な例です:

マクロ.xpp

std::cout << MESSAGE;
#undef MESSAGE

ファイル.cpp:

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

#ifまた、これにより、通常のマクロでは実行できない、引数に友人を使用することもできます。

于 2012-06-04T07:08:52.883 に答える
28

はい、ヘッダーを複数回含めると便利な場合あります (かなり珍しいことですが)。標準的な例は<assert.h>で、 が定義さasssertれているかどうかによって定義が異なりNDEBUGます。そのため、それを含めてから、(通常は条件付きで) NDEBUG の定義を作成し、続いて再度含めて、(少なくとも潜在的に) の異なる定義を使用することは理にかなっていますassert

マクロは、含まれる各時刻 assertの現在の状態に従って再定義されます1NDEBUG<assert.h>

ただし、ほとんどのヘッダーは、冪等になるように苦労しています (つまり、どれだけ頻繁に含まれていても同じ効果が得られるようにするため)。


1 C99、§7.2/1。

于 2012-06-04T07:09:48.227 に答える
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>";
}
于 2012-06-04T07:46:12.993 に答える
4

はい、一度だけ含める方が便利です。そのため、 #pragma once を使用します。C++で:)

編集:

注: #pragma once は移植できません。使用できます

#ifndef FILENAME_H
#define FILENAME_H

移植可能にしたい場合は、代わりにヘッダーファイルの先頭に。

于 2012-06-04T07:06:11.160 に答える
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
于 2012-06-06T11:36:37.517 に答える
-6
#ifndef _INC_HEADER_
#define _INC_HEADER_

//header code

#endif

HEADERヘッダーの名前はどこですか

例えば。main_win.hになります_INC_MAIN_WIN_

于 2012-06-04T07:09:17.120 に答える