Chinaunix首页 | 论坛 | 博客
  • 博客访问: 2308788
  • 博文数量: 527
  • 博客积分: 10343
  • 博客等级: 上将
  • 技术积分: 5565
  • 用 户 组: 普通用户
  • 注册时间: 2005-07-26 23:05
文章分类

全部博文(527)

文章存档

2014年(4)

2012年(13)

2011年(19)

2010年(91)

2009年(136)

2008年(142)

2007年(80)

2006年(29)

2005年(13)

我的朋友

分类: WINDOWS

2010-06-21 15:52:06

C语言中的名字空间, 较少被提及. 下面的写法乍看之下是会让人吃惊的:

#include

struct Foo
{
    int table_id;
    signed int length:4;
} ;

typedef struct Foo Foo;
int main()
{
    Foo Foo;
    printf("size: %lld\n", (long long) sizeof(Foo));
    // Foo t1 = {0};
    return 0;
}

Foo 首先是一个struct的tag名字, 其次又被typedef定义了一个同名的别名. 然后, 在main函数中,
以Foo Foo; 定义了该类型的一个变量, 同样名为Foo.

这样的程序竟然是符合标准的. 原因就在于C语言中有4个名字空间, 当标识符在不同的上下文情境下位于不同的名字空间时, 可同时出现而不会引起冲突.

我查看了C语言标准, 6.2.3 Name Spaces and Identifiers
其中定义的4个名字空间如下:
1. label 单独位于一个名字空间, 由于goto有害论, label受到牵连, 现今其重要性极低.
2. struct, union, enum的名字, 在C标准中用tag一词指代, 它们的名字位于一个名字空间, 也就是说, 如果你已经
struct Foo { ... };
就不能再
enum Foo {... };


3. struct, 或union的成员, 位于由相应的struct或union声明范围内的一个密闭名字空间, 两个不同的struct, 或struct与union的成员, 可以有同样的名字, 这一规则可以递归地施行于struct / union的子成员. 如果它们本身也是一个struct或union的话.

4. 所有其它的一切东西, 比如函数名, 变量名等等.

根据这4条, 上面的程序该如何解释? Foo 重复出现了3次:
struct Tag.
typedef 或
main内的变量名.

根据上面的定义, 作为typedef定义出来的类型名和main内的变量名同属于"其它"类, 应该会出现冲突. 但实际上这样的用法是允许的. 因为在main内通过
Foo Foo;
定义变量Foo时, 第一个Foo的语意只能是typedef定义出来的Foo才合理, 此时作为变量的Foo还没定义完成, 所以没有冲突.

那一行注释起来的
// Foo t1...
如果去掉注释, 就会引起编译错误,

test.c:15: error: expected ';' before 't1'
gcc的这条错误并没提供多少有用的信息.

因为在此时的上下文中, 就有了两个identifier位于同一个名字空间. 而printf中的sizeof(Foo) 究竟是作为typedef定义出来的别名Foo, 还是变量名Foo.

虽然无法从程序运行结果上知道, 但可以确定应该是变量名Foo, 简单的实验加推理可以证实这一点:
将Foo Foo改为char Foo;
此时大小变为1.

推理:
typdef定义的别名其作为域在最外层, 而在main内, 变量Foo暂时性地遮蔽了外层Foo的意义.
对上面程序作如下修改, 得到的结果可以证实:

int main()
{
    {
        char Foo;
        int a = 4, b = a;
        printf("size: %lld\n", (long long)sizeof(Foo) );
    }
    printf("size: %lld\n", (long long)sizeof(Foo) );
    struct Foo t1 = {0};
    return 0;
}

另一个需要注意的地方是, C语言中定义的结构的可见性, 是平坦的,
struct Foo
{
   struct Bar { ... };
};

熟悉C++类型系统的人可能会怀疑是否能直接使用结构Bar, 要不要Foo::, C里面Bar的可用性跟Foo是平级的.
阅读(1131) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~