如果现在回过头去看看“声明是如何形成的”那一节,会发现typedef关键字可以是一个 常规声明的一部分,可以出现在靠近声明开始部分的任何地方。事实上,typedef的格式与变 量声明完全一样,只是多了这个关键字,向你提醒它的实质。
由于typedef看上去跟变量声明完全一样,它们读起来也是一样的。前面•节描述的分析 技巧也同样适用于typedef。普通的声明表示“这个名字是一个指定类型的变量”,而typedef 关键字并不创建一个变量,而是宣称“这个名字是指定类型的同义词”。
一般情况下,typedf用于简洁地表示指向其他东西的指针。典型的例子是signal()原型的声明。signal()是一种系统调用,用于通知运行时系统,当某种特定的“软件中断”发生时调用特定的程序。它的真正名称应是“Call__that_routine _when_this_interrupt_comes_in (:当该中断发生时调用那个程序)”。你调用signal(),并通过参数传递告诉它中断的类型以及用于处理中断的程序。在ANSI C标准中,signal()的声明如下:
void {^signal(int sig, void(*func) (int))) (int);
让我们运用刚刚掌提的技巧来分析这个声明,会发现它的意思如下:
void(*signal( ))(int);
signal是一个函数(具有一些令人胆战心惊的参数),它返回一个函数指针,后者所指向 的函数接受一个int参数并返回void。其中一个恐怖的参数是其本身:
void(*func> (int);
它表示一个函数指针,所指向的函数接受一个int参数,返回值是void。现在,让我们 看一下怎样用typedef来“代表”通用部分,从而进行简化。
typedef void (*pt3:_to_func) (int);
/*它表示ptr_to_func是一个函数指针,该函数 *接受一个int参数,返回值为void。*/
ptr_to—func signal (int, ptr—to—func:);
/*它表不signal是一个函数,它接受两个参数,
*其中一个是int,另一个是ptr_to_func,返回 * 值是 ptr_to_func。
*/
然而,说到typedef就不能不说一下它的缺点。它同样具有与其他声明一样的混乱语法,同样可以把几个声明器塞到一个声明中去。对于结构,除了可以在书写时省掉Struct关键字 之外,typedef并不能提供显著的好处,而少写一个struct其实并没有多大帮助。在任何typedef 声明中,甚至不必把typedef放在声明的开始位置。
操作声明器的一些提示
不要在一个typedef中放入几个声明器,如下所示:
typedef int *ptr/ (fun)(), arr[5];
/* ptr是“指向int的指针”类型,
* fun是“指向返回值为int的函数的指针”类型
* arr是“长度为5的int型数组”类型 */
千万不要把typedef嵌到声明的中间部分,如下所示:
unsigned const long typedef int volatile *kumquat;
typedef为数据类型创趕别名,而不是创建新的数据类型,可以对任何类型进行typedef声明。
typedef int (*array_ptr)[100];
应该只对所希望的变量类型进行typedef声明,为变量类型取一个喜欢的别名。关键字 typedef应该如前所述出现在声明的开始位置。在同一个代码块中,typedef引入的名字不能与 其他标识符同名。
typedef int x[10]和#define x init[10]的区别
前面已经提到过,在typedef和宏文本替换之间存在一个关键性的区别。正确思考这个问 题的方法就是把typedef看成是一种彻底的“封装”类型——在声明它之后不能再往里面增加 别的东西。它和宏的区别体现在两个方面。
首先,可以用其他类型说明符对宏类型名进行扩展,但对typedef所定义的类型名却不能 这样做。如下所示:
unsigned const long typedef int volatile *kumquat;
声明。
typedef int (*array_ptr)[100];
#define peach int unsigned peach i ; /* 没问
typedef int banana;
unsigned banana i; /* 错误! 非法 */
其次,在连续几个变量的声明中,用typedef定义的类型能够保证声明中所有的变S均为 同一种类型,而用#define定义的类型则无法保证。如下所示:
#define int_ptr int * int_ptr chalk, cheese;
经过宏扩展,第二行变为:
int * chalk, cheese;
这使得chalk和cheese成为不同的类型,就好象是辣椒酱与细香葱的区别:chalk足个 指向int的指针,而cheese则是一个int。相反,下面的代码中:
typedef char * char_ptr; char_ptr Bentley, Rolls_Royce;
Bentley和RollS_Royce的类型依然相同。虽然前面的类型名变了,但它们的类型相同, 都是指向char的指针。