命名空间
变体
操作

查找与命名空间

来自 cppreference.cn
< 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++ 文档,关于名称查找