一、
创建易于记忆的类型名
typedef
使用最多的是用于创建易于记忆的类型名。例如:
typedef unsigned char U8;
此声明定义了一个
unsigned char
的同义字
U8
,以后可以用
U8
来代替
unsigned char
,
void measure(U8 * psz);
U8 array[4];
二、 定义结构体
typedef struct tagMyStruct
{ int Num;
char lable;
} MyStruct;
这语句实际上完成两个操作:
1) 定义一个新的结构类型:
struct tagMyStruct :
{ int Num;
char lable;
};
};
tagMyStruct
称为
“tag”
,即
“
标签
”
,实际上是一个临时名字,
struct
关键字和
tagMyStruct
一起,构成了这个结构类型,不论是否有
typedef
,这个结构都存在。
我们可以用 struct tagMyStruct varName 来定义变量,但要注意,使用 tagMyStruct varName 来定义变量是不对的,因为 struct 和 tagMyStruct 合在一起才能表示一个结构类型。
2) typedef 为这个新的结构起了一个名字,叫 MyStruct :
typedef struct tagMyStruct MyStruct;
因此, MyStruct 实际上相当于 struct tagMyStruct ,我们可以使用 MyStruct varName 来定义变量。但是在类型本身还没有建立完成的时候,这个类型的新名字也还不存在,也就是说这个时候编译器还不认识新名字。例如:
我们可以用 struct tagMyStruct varName 来定义变量,但要注意,使用 tagMyStruct varName 来定义变量是不对的,因为 struct 和 tagMyStruct 合在一起才能表示一个结构类型。
2) typedef 为这个新的结构起了一个名字,叫 MyStruct :
typedef struct tagMyStruct MyStruct;
因此, MyStruct 实际上相当于 struct tagMyStruct ,我们可以使用 MyStruct varName 来定义变量。但是在类型本身还没有建立完成的时候,这个类型的新名字也还不存在,也就是说这个时候编译器还不认识新名字。例如:
typedef struct tagNode
{ char *pItem;
pNode pNext; // 错误
} *pNode;
{ char *pItem;
pNode pNext; // 错误
} *pNode;
在上面这段代码中
pNode
新类型名字还没有建立完成,却在定义成员时用到,编译器不能识别,报错。规范做法:
struct tagNode
{ char *pItem;
struct tagNode *pNext;
};
typedef struct tagNode *pNode;
struct tagNode
{ char *pItem;
struct tagNode *pNext;
};
typedef struct tagNode *pNode;
三、 掩饰符号类型。例如当需要定义多个包含 80 个元素的数组 a , b , c 时,可以这样定义:
typedef char Array_eighty[80];
Array_eighty a
,
b
,
c;
也可以这样隐藏指针:
typedef char * pstr;
int mystrcmp(pstr, pstr);
注意,对于带
const
的定义,
const pstr p2
并不等于
const char * p2
。
const pstr p2
和
const long p2
本质上没有区别,都是对变量进行只读限制,只不过此处变量
p2
的数据类型是我们自己定义的而不是系统固有类型而已。因此,
const pstr p2
的含义是:限定数据类型为
char *
的变量
p2
为只读,因此类似
p2++
这样的语句是错误的。
四、 代码简化,引入新类型作为函数指针的同义字。
形式:typedef 返回类型(*新类型)(参数表):
typedef char (*PTRFUN)(int);
PTRFUN pFun;
char glFun(int a)
{ return 0; }
void main()
{ pFun = glFun;
(*pFun)(2);
}
第一行创建了一种
PTRFUN
的类型,并定义这种类型为指向某种函数的指针,这种函数以一个
int
为参数并返回
char
类型。第二行的代码便使用这个新类型定义了变量
pFun
,第三行定义了一个函数
glFun()
。该函数是一个以
int
为参数返回
char
的函数。函数的函数名实际上就是一个指针,函数名指向该函数的代码在内存中的首地址。在
main
函数里将函数
glFun
的地址赋值给变量
pFun
。
main
函数的第二句“
*pFun
”取
pFun
所指向地址的内容,也就是取函数
glFun()
的内容。
对复杂变量建立一个类型别名的方法很简单,只要在传统的变量声明表达式里用类型名替代变量名,然后把关键字
typedef
加在该语句的开头就行了。
例,新定义类型
pFun
:
>1. int *(*a[5])(int, char*);
typedef int *(*pFun)(int, char*);
>2. void (*b[10]) (void (*)());
>2. void (*b[10]) (void (*)());
typedef void (*pFunParam)();
typedef void (*pFun)(pFunParam);
>3. doube(*)() (*pa)[9];
>3. doube(*)() (*pa)[9];
typedef double(*pFunParam)();
typedef pFunParam (*pFun)[9];
五、 typedef 和存储类关键字( storage class specifier )
typedef 就像 auto , extern , mutable , static ,和 register 一样,是一个存储类关键字。这并是说 typedef 会真正影响对象的存储特性;它只是说在语句构成上, typedef 声明看起来象 static , extern 等类型的变量声明。
typedef register int FAST_COUNTER; // 错误
编译通不过。问题出在你不能在声明中有多个存储类关键字。因为符号 typedef 已经占据了存储类关键字的位置,在 typedef 声明中不能用 register (或任何其它存储类关键字)。