曙海教育集团论坛开发语言培训专区C++语言开发 → C(不讨论C++)语言


  共有5290人关注过本帖树形打印

主题:C(不讨论C++)语言

美女呀,离线,留言给我吧!
wangxinxin
  1楼 个性首页 | 博客 | 信息 | 搜索 | 邮箱 | 主页 | UC


加好友 发短信
等级:青蜂侠 帖子:1393 积分:14038 威望:0 精华:0 注册:2010-11-12 11:08:23
C(不讨论C++)语言  发帖心情 Post By:2010-12-10 14:26:54

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

#include <stdio.h>

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

typedef struct Foo Foo;
int main()
{
    Foo Foo;
    printf("size: %lld ", (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 ", (long long)sizeof(Foo) );
    }
    printf("size: %lld ", (long long)sizeof(Foo) );
    struct Foo t1 = {0};
    return 0;
}

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

熟悉C++类型系统的人可能会怀疑是否能直接使用结构Bar, 要不要Foo::, C里面Bar的可用性跟Foo是平级的.本篇文章


支持(0中立(0反对(0单帖管理 | 引用 | 回复 回到顶部

返回版面帖子列表

C(不讨论C++)语言








签名