2007-10-23

typedef howto

函数指针的声明可能是C语言中最复杂的声明了。

比如标准C中信号捕捉函数signal的实际声明如下:

void (* signal(int sig, void(*func)(int)))(int);

它的含义是:

signal是一个函数,其参数为整型 int sig以及一个指向函数的指针,这个被指向的函数接受一个整型的参数并返回值void。同时signal函数本身的返回值同他的一个参数一样,也是一个指向接受一个整型参数并返回void的函数指针。

horrible !

但我们在手册中看到的接口声明并非如此,而是非常简洁易读的如下形式:

sighandler_t signal(int signum, sighandler_t handler);

这是因为使用了typedef的缘故

typedef void (*sighandler_t)(int);

这样就可以用简洁的sighandler_t代表一复杂的函数指针了。

由此可见typedef的魔力。

经常用到typedef的地方还有结构体的声明,使用typedef可以少敲不少字。

typedef struct {
    int bar;
}foo,*pfoo; 

foo var;
pfoo pvar;
pvar = &var;

如果结构体中有指向自身的指针(这很常见,不是么?),上面的方法就不好用了 ,但我们另有解决方案:

typedef struct foo foo;

struct foo{
    int bar;
    foo * pbar;
};

foo var;

细心发现,typedef对于未存在的类型也能指定别名。

一个小陷阱:typedef与define的区别。

“typedef和宏文本替换之间存在一个关键性的区别……把typedef看作一中彻底的‘封装类型’ -- 在声明它后不能在向里面添加别的东西” --- C专家编程

#define foo int
unsigned foo i; // this is OK

typedef int bar
unsigned bar j; // illegal!

其次typedef可以保证声明中所有变量都是同一种类型。

例如:

#define foo int * 
typedef  int * bar;

foo i,j; // 等同于 int * i,j; 则i为指针,j为整型

bar m,n; // m,n都是指向整型的指针

结论: 使用define可能会引起潜在的错误,所以,还是使用typedef吧。

适度地使用typedef可以使程序简明清晰,不过,滥用typedef也是不好的,非常不好。我尤其不喜欢用typede给指向结构体指针取别名,谁希望与同一个结构体相关的变量出现好几个在字面上看起来不相关的名字?

–EOF–