名前空間
変種
操作

ルックアップと名前空間

From cppreference.com
< c‎ | language

Cプログラム中で識別子に遭遇すると、その識別子を導入し、かつ現在スコープ内にある宣言を見つけるためにルックアップが実行されます。C言語では、それらの識別子が名前空間 (name spaces) と呼ばれる異なるカテゴリに属している場合、同じ識別子に対して複数の宣言が同時にスコープ内に存在することを許可します。

1) ラベル名前空間: ラベルとして宣言されたすべての識別子。
2) タグ名: 構造体共用体列挙型の名前として宣言されたすべての識別子。これら3種類のタグは1つの名前空間を共有することに注意してください。
3) メンバ名: いずれか1つの構造体または共用体のメンバとして宣言されたすべての識別子。各構造体および共用体は、この種類の独自の名前空間を導入します。
4) グローバル属性名前空間: 標準で定義された属性トークン、または実装定義の属性接頭辞。
5) 非標準属性名: 属性接頭辞に続く属性名。各属性接頭辞は、それが導入する実装定義の属性のために個別の名前空間を持ちます。
(C23以降)
6) その他すべての識別子。(1-5)と区別するために通常の識別子 (ordinary identifiers) と呼ばれます (関数名、オブジェクト名、typedef名、列挙定数)。

ルックアップの時点で、識別子の名前空間はそれがどのように使用されるかによって決定されます。

1) goto文のオペランドとして現れる識別子は、ラベル名前空間で検索されます。
2) キーワード structunion、または enum の後に続く識別子は、タグ名前空間で検索されます。
3) メンバアクセスまたはポインタを介したメンバアクセス演算子の後に続く識別子は、メンバアクセス演算子の左オペランドによって決定される型のメンバの名前空間で検索されます。
4) 属性指定子 ([[...]]) 内に直接現れる識別子は、グローバル属性名前空間で検索されます。
5) 属性接頭辞に続く :: トークンの後に続く識別子は、その属性接頭辞によって導入された名前空間で検索されます。
(C23以降)
6) その他すべての識別子は、通常の識別子の名前空間で検索されます。

目次

[編集] 注釈

マクロの名前は、意味解析の前にプリプロセッサによって置換されるため、どの名前空間にも属しません。

typedef宣言を用いて、構造体/共用体/列挙型の名前を通常の識別子の名前空間に注入するのが一般的な慣習です。

struct A { };       // introduces the name A in tag name space
typedef struct A A; // first, lookup for A after "struct" finds one in tag name space
                    // then introduces the name A in the ordinary name space
struct A* p;        // OK, this A is looked up in the tag name space
A* q;               // OK, this A is looked up in the ordinary name space

同じ識別子が2つの名前空間にわたって使用されるよく知られた例として、POSIXヘッダsys/stat.hの識別子 stat があります。これは、通常の識別子として使用される場合は関数を命名し、タグとして使用される場合は構造体を示します

C++とは異なり、列挙定数は構造体のメンバではなく、その名前空間は通常の識別子の名前空間です。また、Cには構造体スコープがないため、列挙定数のスコープは、その構造体宣言が現れるスコープになります。

struct tagged_union {
   enum {INT, FLOAT, STRING} type;
   union {
      int integer;
      float floating_point;
      char *string;
   };
} tu;
 
tu.type = INT; // OK in C, error in C++

標準属性、属性接頭辞、または非標準の属性名がサポートされていない場合、無効な属性自体はエラーを引き起こすことなく無視されます。

(C23以降)

[編集]

void foo (void) { return; } // ordinary name space, file scope
struct foo {      // tag name space, file scope
    int foo;      // member name space for this struct foo, file scope
    enum bar {    // tag name space, file scope
        RED       // ordinary name space, file scope
    } bar;        // member name space for this struct foo, file scope
    struct foo* p; // OK: uses tag/file scope name "foo"
};
enum bar x; // OK: uses tag/file-scope bar
// int foo; // Error: ordinary name space foo already in scope 
//union foo { int a, b; }; // Error: tag name space foo in scope
 
int main(void)
{
    goto foo; // OK uses "foo" from label name space/function scope
 
    struct foo { // tag name space, block scope (hides file scope)
       enum bar x; // OK, uses "bar" from tag name space/file scope
    };
    typedef struct foo foo; // OK: uses foo from tag name space/block scope
                            // defines block-scope ordinary foo (hides file scope)
    (foo){.x=RED}; // uses ordinary/block-scope foo and ordinary/file-scope RED
 
foo:; // label name space, function scope
}

[編集] 参照

  • C17標準 (ISO/IEC 9899:2018)
  • 6.2.3 識別子の名前空間 (p: 29-30)
  • C11標準 (ISO/IEC 9899:2011)
  • 6.2.3 識別子の名前空間 (p: 37)
  • C99標準 (ISO/IEC 9899:1999)
  • 6.2.3 識別子の名前空間 (p: 31)
  • C89/C90標準 (ISO/IEC 9899:1990)
  • 3.1.2.3 識別子の名前空間

[編集] 関連項目

C++ ドキュメント名前探索
English 日本語 中文(简体) 中文(繁體)