C/C++ ヘッダーファイルにおけるインクルードガードの命名規則を示します。
C 標準では、アンダースコアで始まる特定の識別子は「実装系」(コンパイラ、標準ライブラリ、OS) のために予約されています。ユーザーコードでこれらの識別子を使用した場合、未定義動作 (undefined behavior) となります。
以下の識別子はファイルスコープにおいて予約されています。
| パターン | 予約先 | 例 |
|---|---|---|
アンダースコア + 大文字で始まる (_[A-Z]...) |
実装系 (いかなる用途でも予約) | _LIBCALC_H, _FMTIO_UTIL_H |
アンダースコア 2 つで始まる (__...) |
実装系 (いかなる用途でも予約) | __GNUC__, __cplusplus |
アンダースコア 1 つで始まる (_[a-z]...) |
通常の識別子としてはファイルスコープで予約 | _count, _internal |
コンパイラやライブラリが提供するマクロ (_WIN32, __GNUC__, _MSC_VER など) がこのパターンに従っているのは、予約済み名前空間に属しているためです。
この予約規則は以下の規格で定義されています。
C11 §7.1.3 から該当部分を引用します。
All identifiers that begin with an underscore and either an uppercase letter or another underscore are always reserved for any use.
All identifiers that begin with an underscore are always reserved for use as identifiers with file scope in both the ordinary and tag name spaces.
C++ 標準でも同等の規則が定義されています (C++20 では [lex.name] および [reserved.names])。
ヘッダーファイル名を大文字に変換し、ハイフンやドットをアンダースコアに置き換えた名前を使用します。先頭にアンダースコアを付けません。
/* fmtio-util.h の場合 */
#ifndef FMTIO_UTIL_H
#define FMTIO_UTIL_H
/* ... */
#endif /* FMTIO_UTIL_H *//* 正しい例 */
#ifndef LIBCALC_H
#define LIBCALC_H
/* 誤った例: アンダースコア + 大文字は実装系に予約されている */
#ifndef _LIBCALC_H
#define _LIBCALC_H_WIN32, _MSC_VER, __GNUC__ 等のコンパイラが定義するマクロは、予約済み名前空間を使用することが規格上正しい識別子です。これらはユーザーが定義するものではなく、コンパイラや OS が提供するものであるため、#if defined(_WIN32) のような判定はそのまま使用します。
/* コンパイラ定義マクロの判定: 変更不要 */
#ifndef _WIN32
#define CALC_API
#else
#define CALC_API __declspec(dllexport)
#endif