首页
学习
活动
专区
工具
TVP
发布
精选内容/技术社群/优惠产品,尽在小程序
立即前往

Lookup and name spaces

当在C程序中遇到标识符时,执行查找以找到引入该标识符的声明,该声明当前处于范围内。如果这些标识符属于不同的类别(称为名称空间),那么C允许同一标识符的多个声明同时处于同一范围内:

1)标签名称空间:将所有标识符声明为标签。

2)标签名称:声明为结构名称,联合和枚举类型的所有标识符。请注意,所有三种标签共享一个名称空间。

3)成员名称:声明为任何一个结构或联合的成员的所有标识符。每个结构和联合都引入了它自己的这种名称空间。

4)所有其他标识符,称为普通标识符以区分(1-3)(函数名称,对象名称,typedef名称,枚举常量)。

在查找时,标识符的名称空间由其使用方式决定:

1)在标签名称空间中查找作为goto语句的操作数出现的标识符。

2)随后的关键字标识符structunionenum在标签名称空间中查找。

3)通过指针操作符访问成员访问或成员访问之后的标识符在由成员访问操作符的左操作数确定的类型的成员的名称空间中查找。

4)在普通标识符的名称空间中查找所有其他标识符。

笔记

宏的名称不是任何名称空间的一部分,因为它们在语义分析之前被预处理器替换。

通常的做法是使用typedef声明将struct / union / enum名称注入普通标识符的名称空间中:

代码语言:javascript
复制
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

跨两个名称空间使用相同标识符的着名示例是statPOSIX标头中的标识符sys/stat.h。它用作普通标识符时指定一个函数,并在用作标记时指示一个结构体

与C ++不同,枚举常量不是结构成员,它们的名称空间是普通标识符的名称空间,并且由于C中没有结构作用域,因此它们的作用域是结构声明出现的范围:

代码语言:javascript
复制
struct tagged_union 
{
   enum {INT, FLOAT, STRING} type;
   int integer;
   float floating_point;
   char *string;
} tu;
 
tu.type = INT; // OK in C, error in C++

代码语言:javascript
复制
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
}

参考

  • C11 standard (ISO/IEC 9899:2011):
    • 6.2.3 Name spaces of identifiers (p: 37)
  • C99 standard (ISO/IEC 9899:1999):
    • 6.2.3 Name spaces of identifiers (p: 31)
  • C89/C90 standard (ISO/IEC 9899:1990):
    • 3.1.2.3 Name spaces of identifiers

扫码关注腾讯云开发者

领取腾讯云代金券