標準化作業の初期の段階において ANSI 規格委員会は、ライブラリ関数、マクロ、およびヘッダーファイルを ANSI C の一部として含むことを選択しました。この決定は本当に移植可能な C プログラムを書くために必要でしたが、一方では、ユーザーから ANSI C に対してもっとも否定的な意見 (つまり、予約名が多すぎる) が出る理由となりました。
この節では、さまざまな予約名のカテゴリとその予約名が必要な基本的な理由を示します。最後には、プログラムで予約名を使用しないようにするための規則を示します。
既存の実装に一致させるため、ANSI C 委員会は printf や NULL などの名前を選択しました。しかしその結果、C プログラムで自由に使用できる名前が減りました。
一方、標準化以前では、実装者は自由に新しいキーワードをコンパイラに追加し、新しい名前をヘッダーに追加できました。したがって、どのプログラムもリリースが変わるだけでコンパイルできるかどうか保証されず、まして、異なるベンダーの実装間では移植できませんでした。
その結果、委員会は ANSI C に準拠する実装では余分な名前を使用してはならない (特定の形式の名前を除く) という厳しい決定を下しました。この決定には、ほとんどの C コンパイルシステムがほぼ準拠できます。しかし、標準ヘッダーには、32 個のキーワードと約 250 個の名前が含まれています。どのキーワードまたは名前も特定の命名パターンに従っているとは限りません。
標準ヘッダーは次のとおりです。
表 E-4 標準ヘッダーassert.h | locale.h | stddef.h |
ctype.h | math.h | stdio.h |
errno.h | setjmp.h | stdlib.h |
float.h | signal.h | string.h |
limits.h | stdarg.h | time.h |
ほとんどの実装では、さらに多くのヘッダーが用意されています。しかし、ANSI C に厳密に準拠するプログラムが使用できるのは、上記ヘッダーだけです。
これらヘッダーの一部の内容については、他の規格ではわずかに異なります。たとえば、POSIX (IEEE 1003.1) は、fdopen を stdio.h で宣言するように指定しています。これら 2 つの規格が共存するために、POSIX では、このような追加の名前が存在することを保証するためには任意のヘッダーをインクルードする前にマクロ _POSIX_SOURCE を #define で定義しなければならないと規定しています。X/Open の『Portability Guide』によると、X/Open もこのマクロ方式を使用して拡張しています。X/Open のマクロは _XOPEN_SOURCE です。
ANSI C は、標準ヘッダーがそれ自身だけで完結し、べき等 (何度指定しても同じ) であることを要求しています。どの標準ヘッダーも、その前後で他のヘッダーを #include でインクルードする必要はありません。標準ヘッダーは何度 #include でインクルードしても、問題は発生しません。ANSI C 規格では、安全なコンテキストにおいてのみ、標準ヘッダーを #include でインクルードすることを要求します。したがって、ヘッダーで使用される名前は変更されないことが保証されます。
ANSI C 規格は、標準ライブラリについて、より多くの制限を実装に課しています。過去において、ほとんどのプログラマは UNIX システムでは独自の関数に read や write などの名前を使用しないように学びました。ANSI C では、予約されている名前だけを実装内の参照で使用するように規定しています。
したがって ANSI C 規格では、実装で使用する可能性があるすべての名前のサブセットが予約されています。この名前のクラスは下線で始まり、もう 1 つの下線または大文字の英字が続く識別子から構成されます。この名前のクラスは、次の正規表現に一致するすべての名前を含みます。
_[_A-Z][0-9_a-zA-Z]*
厳密には、プログラムがこのような識別子を使用する場合、その動作は未定義です。したがって、_POSIX_SOURCE (または、_XOPEN_SOURCE) を使用するプログラムの動作は未定義です。
ただし、動作がどれぐらい未定義なのかは異なります。POSIX 準拠の実装で _POSIX_SOURCE を使用する場合、ユーザーのプログラムの未定義の動作が特定のヘッダー内に追加された特定の名前から構成されていることと、受け入れられる標準にユーザーのプログラムが準拠していることは予測できます。ANSI C 規格におけるこの故意の抜け道により、実装は外見上互換性のない仕様に準拠できます。一方、POSIX 規格に準拠しない実装は、_POSIX_SOURCE などの名前に遭遇したとき、任意の方法で動作できます。
ANSI C 規格では、下線で始まる他のすべての名前が (局所的なスコープではなく) ヘッダーファイルにおける通常のファイルのスコープの識別子として、および構造体と共用体のタグとして使用するために予約されています。従来通り、_filbuf と _doprnt という名前の関数によりライブラリの隠れた部分を実装することはできます。
明示的に予約されたすべての名前に加えて、ANSI C 規格は、次の特定のパターンに一致する名前を (実装と将来の規格用に) 予約しています。
表 E-5 拡張用の予約名
ファイル |
予約名のパターン |
---|---|
errno.h | E[0-9A-Z].* |
ctype.h | (to|is)[a-z].* |
locale.h | LC_[A-Z].* |
math.h |
<現在の関数名> [fl] |
signal.h | (SIG|SIG_)[A-Z].* |
stdlib.h | str[a-z].* |
string.h | (str|mem|wcs)[a-z].* |
上記リストにおいて、大文字の英字で始まる名前はマクロで、関連するヘッダーがインクルードされるときだけ予約されます。残りの名前は関数を示し、大域的なオブジェクトや関数を指定する場合には使用できません。
ANSI C の予約名と衝突しないようにするためには、次の 4 つの簡単な規則に従う必要があります。
すべてのシステムヘッダーは、ユーザーのソースファイルの最初に #include でインクルードする (_POSIX_SOURCE または _XOPEN_SOURCE (あるいは、その両方) の #define 行がある場合は、その後でインクルードする)
下線で始まる名前は定義または宣言しない
すべてのファイルスコープのタグと通常名の最初の数文字では、下線または大文字の英字を使用する。stdarg.h または varargs.h 内の va_ 接頭辞に注意する
すべてのマクロ名の最初の数文字では、数字または小文字の英字を使用する。 errno.h を #include でインクルードする場合、E で始まるほとんどすべての名前は予約されています。
ほとんどの実装はデフォルトで標準ヘッダーに名前を追加しているため、これらの規則は一般的なガイドラインに過ぎません。