Hatena::ブログ(Diary)

masugata_kの日記

2008-01-28

#include ガードにファイル名を入れるのは止めませんか?

#include ガードといえば、大体こんな感じのがメジャーかと思う:

sample.h の #include ガード
#ifndef SAMPLE_H
#define SAMPLE_H

// 宣言・定義など

#endif // ifndef SAMPLE_H

実を言えば、こういう #include ガードがあんまり好きじゃない。

もちろん、#include ガードそのものが嫌いなわけじゃない。というか、#include ガードは絶対に必要*1なもので、好き嫌いでどうこうする問題じゃない。嫌いなのは、#include ガードに使われている SAMPLE_H というマクロ名だ。

#include ガードのマクロ名は絶対に一意でなければならないからヘッダのファイル名をマクロ名に織り込むわけだが、たとえば、<some_header.h><some/header.h>#include ガードはどちらも SOME_HEADER_H になってしまわないだろうか?

このようなマクロ名の衝突の危険性もさることながら、もっと嫌なことがある。#include ガードにファイル名を織り込むと、ファイル名を変更するときに邪魔になるのだ。些細なことかもしれない。だが、ディレクトリ名を変更したりした場合の作業量は決して馬鹿にはならない*2。そして、その“面倒くささ”がリファクタリングを妨害し、プログラムは段々と理解不能な代物へと“腐敗”していく。

そんなわけで、僕は、こんな感じの #include ガードを使っている:

#ifndef INCLUDE_GUARD_UUID_0FA2482C_F796_4715_A360_E088A24F0042
#define INCLUDE_GUARD_UUID_0FA2482C_F796_4715_A360_E088A24F0042

// 宣言・定義など

#endif // ifndef INCLUDE_GUARD_UUID_0FA2482C_F796_4715_A360_E088A24F0042

何かのソースを見たときに UUID で #include ガードの一意性を確保しているのを見て*3、パクった。uuidgen を実行するのがちょっと面倒くさいが、まあ、大した手間じゃない。

ちなみに、some_header.h と some/header.h を区別するために #define SOME__HEADER_H とやるのは禁じ手だ。_SOME_HEADER_H のようにする人もたまに見かけるが、それも禁じ手:

C++ 標準 *4 ― 17.4.3.1.2 Global names
Certain sets of names and function signatures are always reserved to the implementation:
  • Each name that contains a double underscore (__) or begins with an underscore followed by an upper-case letter (2.11) is reserved to the implementation for any use.
  • Each name that begins with an underscore is reserved to the implementation for use as a name in the global namespace.

*1#pragma once とか #import とかは好きだが、いかんせん、使えない環境がある以上は採用できない。

*2Java 慣れしてしまったせいか、クラスごとにヘッダファイルを分けて名前空間に対応させたディレクトリ階層に置くクセがついてしまった。

*3:多分、Visual C++ が自動生成したヘッダだったと思う。

*4ISO/IEC 14882

トラックバック - http://d.hatena.ne.jp/masugata_k/20080128/1201541953