typedef作为类型定义关键字,用于在原有数据类型(包括基本类型、构造类型和指针等)的基础上,由用户自定义新的类型名称。
在编程中使用typedef的好处,除了为变量取一个简单易记且意义明确的新名称之外,还可以简化一些比较复杂的类型声明。比如:
typedef int INT32;
将INT32定义为与int具有相同意义的名字,这样类型INT32就可用于类型声明和类型转换了,它和类型int完全相同。比如:
INT32 a; // 定义整型变量a
(INT32) b; // 将其它的类型b转换为整型
既然已经有了int这个名称,为什么还要再取一个名称呢?主要是为了提高程序的可移植性。比如,某种微处理器的int为16位,long为32位。如果要将该程序移植到另一种体系结构的微处理器,假设编译器的int为32位,long为64位,而只有short才是16位的,因此必须将程序中的int全部替换为short,long全部替换为int,如此这样修改势必工作量巨大且容易出错。如果将它取一个新的名称,然后在程序中全部用新取的名称,那么要移植的工作仅仅只是修改定义这些新名称即可。也就是说,只需要将以前的:
typedef int INT16;
typedef long INT32;
替换成:
typedef short INT16;
typedef int INT32;
由此可见,typedef声明并没有创建一个新类型,而是为某个已经存在的类型增加一个新的名字而已。用这种方式声明的变量与通过声明方式声明的变量具有完全相同的属性。
至于typedef如何简化复杂的类型声明,将在后续的章节中详细阐述。
综上所述,如果在变量定义的前面加上typedef,即可定义该变量的类型。比如:
int size;
这里定义了一个整型变量size,当加上typedef后:
typedef int size;
那么,size就成为了上面的size变量的类型,即int类型。既然size是一个类型,当然可以用它来定义另外一个变量。即:
size a;
类似于变量的类型定义,也可以用typedef声明新的类型,比如:
char *ptr_to_char; // 声明ptr_to_char为一个指向字符的指针
typedef char ptr_to_char; // 声明ptr_to_char为指向char的指针类型
ptr_to_char pch; // 声明pch是一个指向字符的指针
对于初学者来说,也许会产生一个这样的疑问,为什么不使用#define创建新的类型名?比如:
#define ptr_to_char char*
ptr_to_char pch1, pch2;
由于有了“#define ptr_to_char char*”,因此“ptr_to_char pch1, pch2”可以展开为
char *pch1, pch2;
所以pch2为char型变量。如果用typedef来定义的话,其代码如下:
typedef char* ptr_to_char;
ptr_to_char pch1, pch2;
则“ptr_to_char pch1, pch2”等价于
char *pch1;
char *pch2;
因此,pch1、pch2都是指针。
虽然#define语句看起来象typedef,但实际上却有本质上的差别。对于#define来说,仅在编译前对源代码进行了字符串替换处理;而对于typedef来说,它建立了一个新的数据类型别名。由此可见,只是将pch1定义为指针变量,却并没有实现程序员的意图,而是将pch2定义成了char型变量。
typedef的四个用途和两个陷阱
用途一:
定义一种类型的别名,而不只是简单的宏替换。可以用作同时声明指针型的多个对象。比如:
char*
pa,
pb;
//
这多数不符合我们的意图,它只声明了一个指向字符变量的指针,
//
和一个字符变量;
以下则可行:
typedef
char*
PCHAR;
//
一般用大写
PCHAR
pa,
pb;
//
可行,同时声明了两个指向字符变量的指针
虽然:
char
*pa,
*pb;
也可行,但相对来说没有用typedef的形式直观,尤其在需要大量指针的地方,typedef的方式更省事。
用途二:
用在旧的C代码中(具体多旧没有查),帮助struct。以前的代码中,声明struct新对象时,必须要带上struct,即形式为:
struct
结构名
对象名,如:
struct
tagPOINT1
{
int
x;
int
y;
};
struct
tagPOINT1
p1;
而在C++中,则可以直接写:结构名
对象名,即:
tagPOINT1
p1;
估计某人觉得经常多写一个struct太麻烦了,于是就发明了:
typedef
struct
tagPOINT
{
int
x;
int
y;
}POINT;
POINT
p1;
//
这样就比原来的方式少写了一个struct,比较省事,尤其在大量使用的时候
或许,在C++中,typedef的这种用途二不是很大,但是理解了它,对掌握以前的旧代码还是有帮助的,毕竟我们在项目中有可能会遇到较早些年代遗留下来的代码。
用途三:
用typedef来定义与平台无关的类型。
比如定义一个叫
REAL
的浮点类型,在目标平台一上,让它表示最高精度的类型为:
typedef
long
double
REAL;
在不支持
long
double
的平台二上,改为:
typedef
double
REAL;
在连
double
都不支持的平台三上,改为:
typedef
float
REAL;
也就是说,当跨平台时,只要改下
typedef
本身就行,不用对其他源码做任何修改。
标准库就广泛使用了这个技巧,比如size_t。
另外,因为typedef是定义了一种类型的新别名,不是简单的字符串替换,所以它比宏来得稳健(虽然用宏有时也可以完成以上的用途)。
用途四:
为复杂的声明定义一个新的简单的别名。方法是:在原来的声明里逐步用别名替换一部分复杂声明,如此循环,把带变量名的部分留到最后替换,得到的就是原声明的最简化版。举例:
1.
原声明:int
*(*a[5])(int,
char*);
变量名为a,直接用一个新别名pFun替换a就可以了:
typedef
int
*(*pFun)(int,
char*);
原声明的最简化版:
pFun
a[5];
2.
原声明:void
(*b[10])
(void
(*)());
变量名为b,先替换右边部分括号里的,pFunParam为别名一:
typedef
void
(*pFunParam)();
再替换左边的变量b,pFunx为别名二:
typedef
void
(*pFunx)(pFunParam);
原声明的最简化版:
pFunx
b[10];
3.
原声明:doube(*)()
(*e)[9];
变量名为e,先替换左边部分,pFuny为别名一:
typedef
double(*pFuny)();
再替换右边的变量e,pFunParamy为别名二
typedef
pFuny
(*pFunParamy)[9];
原声明的最简化版:
pFunParamy
e; |