命名空间
变体
操作

查找和命名空间

来自 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++ 文档 针对 名称查找