Chinaunix首页 | 论坛 | 博客
  • 博客访问: 335270
  • 博文数量: 79
  • 博客积分: 2466
  • 博客等级: 大尉
  • 技术积分: 880
  • 用 户 组: 普通用户
  • 注册时间: 2006-02-07 16:47
文章分类

全部博文(79)

文章存档

2014年(3)

2012年(7)

2011年(14)

2010年(2)

2009年(2)

2008年(2)

2007年(18)

2006年(31)

分类: C/C++

2006-06-11 21:59:04

如果一个struct tag和一个typedef定义的类型名相同,会怎么样?不会有编译错误,但是理解起来,尤其是不熟悉的话,还是有一点困难。看下面的例子。
 
#include
#include
#include "assert.h"
#include "mem.h"

//#include "list.h"
#ifndef LIST_INCLUDED
#define LIST_INCLUDED
#define T List_T
typedef struct T *T;
/* C语言中,所有的结构体、联合体、枚举类型的名字共享一个名字空间;所有变量名、函数名和类型名(指typedef定义的类型名)共享另外一个名字空间。所以
typedef struct List_T *List_T;
这样的typedef是合法的,不会有名字冲突。但是这样定义仍然会带来一定的理解上的困难。下面结合具体实现详细说明。注意#define定义的宏在进一步编译之前做字符串替换。
*/
struct T {
    T rest;
/* 注意在上面的成员定义里T被替换为List_T,C语言中不能将结构体的名字作为类型名直接使用,因此此处只能把List_T解释成为typedef定义的类型名,rest的类型是struct List_T *。
*/
    void *first;
};
extern T      List_append (T list, T tail);
extern T      List_copy   (T list);
extern T      List_list   (void *x, ...);
/* irrelevent code lines omitted */
#undef T
#endif

#define T List_T
T List_push(T list, void *x) {
    T p;
    NEW(p);
    p->first = x;
    p->rest  = list;
    return p;
}
T List_list(void *x, ...) {
    va_list ap;
    T list, *p = &list;
/* 在上面的定义里,p的类型是T *。T在宏替换过程中被替换为List_T。注意这里的List_T不是结构体名字用作类型名(这在C语言中是不允许的),那么List_T必须被解释为typedef定义的类型名。p的类型是List_T *,即struct List_T **。
*/
    va_start(ap, x);
    for ( ; x; x = va_arg(ap, void *)) {
        NEW(*p);
/* NEW这个宏是在mem.h中定义的:
#define  NEW(q) ((q) = ALLOC((long)sizeof *(q)))
为了方便说明,宏ALLOC的具体实现不再详细解释,可以认为ALLOC基本上和malloc的作用是一样的。
结合上述对变量p的类型分析可知,NEW(*p)中,宏参数q的类型和*p的类型是一样的,即struct List_T *。所以宏定义中sizeof *(q)取得的size值,是对q的类型再次解引用之后的struct List_T类型的size。
上述的宏展开后的结果是:
((*p) = ALLOC((long)sizeof *(*p)));
这个宏所做的工作就是分配一个新的struct List_T类型的结构体,并且让*p指向它。
*/
        (*p)->first = x;
        p = &(*p)->rest;
    }
    *p = NULL;
    va_end(ap);
    return list;
}
阅读(1271) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~