名稱空間
變體
操作

查詢與名稱空間

來自 cppreference.com
< c‎ | 語言

在 C 程式中遇到識別符號時,會執行查詢以定位引入該識別符號且當前在作用域中宣告。如果這些識別符號屬於不同的類別(稱為名稱空間),C 允許同一識別符號的多個宣告同時在作用域中。

1) 標籤名稱空間:所有宣告為標籤的識別符號。
2) 標記名:所有宣告為結構體聯合體列舉型別名稱的識別符號。請注意,這三種標記共享一個名稱空間。
3) 成員名:所有宣告為任何結構體聯合體成員的識別符號。每個結構體和聯合體都引入了其自己的此類名稱空間。
4) 全域性屬性名稱空間:由標準或實現定義的屬性字首定義的屬性標記
5) 非標準屬性名:跟隨屬性字首的屬性名。每個屬性字首都有一個單獨的名稱空間,用於它引入的實現定義的屬性。
(自 C23 起)
6) 所有其他識別符號,稱為普通識別符號,以區別於(1-5)(函式名、物件名、typedef 名、列舉常量)。

在查詢時,識別符號的名稱空間由其使用方式決定。

1) 作為goto 語句的操作數出現的識別符號在標籤名稱空間中查詢。
2) 跟隨關鍵字structunionenum的識別符號在標記名稱空間中查詢。
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

一個在兩個名稱空間中使用相同識別符號的著名例子是 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++ 文件,關於名稱查詢