1.简介
在实际编程开发中,为了能让一些类型更加通用、可识别,常常需要为其重新定义一个名称。
比如在windows系统开发中,就会将基本的数据类型重新定义一个名称用来标识某些类型。
一个常见的例子就是句柄HANDLE
这个类型,其本质上其实就是一个void *
类型,但void*
仅仅只表示了一个指针,而HANDLE
这个名字却可以标识这是一个句柄。
虽然两者本质上没有任何区别,但对于程序员来说,HANDLE
明显会被void*
更加有辨识度。
而为类型重新定义一个名称的方式就是使用typedef
这个关键字,语法如下:
typedef type name;
其中type
代表类型名,name
代表别名。
比如下面代码中,typedef
命令为类型unsign char
起别名BYTE
,然后就可以使用BYTE
声明变量。
typedef unsigned char BYTE;
BYTE c = 'z';
typedef 可以一次指定多个别名,比如下面一次性为int
类型起了三个别名:
typedef int antelope, bagel, mushroom;
正如开头所说,typedef
还 可以为指针起别名:
typedef int* intptr;
int a = 10;
intptr x = &a;
上面示例中,intptr
是int*
的别名,不过使用的时候要小心,这样不容易看出来变量x
是一个指针类型。
typedef
也可以用来为数组类型起别名:
typedef int five_ints[5];
five_ints x = {11, 22, 33, 44, 55};
上面示例中,five_ints
是一个数组类型,包含5个整数。
typedef 为函数起别名的写法如下。
typedef signed char (*fp)(void);
上面示例中,类型别名fp
是一个指针,代表函数signed char (*)(void)
,这也称为函数指针。
2.主要好处
typedef
为类型起别名的好处主要有下面几点。
(1)更好的代码可读性。
typedef char* STRING;
STRING name;
上面示例为字符指针起别名为STRING
,以后使用STRING
声明变量时,就可以轻易辨别该变量是字符串。
(2)为 struct、union、enum 等命令定义的复杂数据结构创建别名,从而便于引用。
struct treenode {
// ...
};
typedef struct treenode* Tree;
上面示例中,Tree
为struct treenode*
的别名。
typedef 也可以与 struct 定义数据类型的命令写在一起。
typedef struct animal {
char* name;
int leg_count, speed;
} animal;
上面示例中,自定义数据类型时,同时使用typedef
命令,为struct animal
起了一个别名animal
。
这种情况下,C 语言允许省略 struct 命令后面的类型名:
typedef struct {
char *name;
int leg_count, speed;
} animal;
上面示例相当于为一个匿名的数据类型起了别名animal
。
(3)typedef 方便以后为变量改类型。
typedef float app_float;
app_float f1, f2, f3;
上面示例中,变量f1
、f2
、f3
的类型都是float
,如果以后需要为它们改类型,只需要修改typedef
语句即可。
typedef long double app_float;
上面命令将变量f1
、f2
、f3
的类型都改为long double
。
(4)可移植性
某一个值在不同计算机上的类型,可能是不一样的。
比如下面的代码在32位整数的计算机没有问题,但是在16位整数的计算机就会出错:
int i = 100000;
C 语言的解决办法,就是提供了类型别名,在不同计算机上会解释成不同类型,比如int32_t
:
int32_t i = 100000;
上面示例将变量i
声明成int32_t
类型,保证它在不同计算机上都是32位宽度,移植代码时就不会出错。
这一类的类型别名都是用 typedef 定义的:
typedef long int ptrdiff_t;
typedef unsigned long int size_t;
typedef int wchar_t;
这些整数类型别名都放在头文件stdint.h
,不同架构的计算机只需修改这个头文件即可,而无需修改代码。
因此,typedef
有助于提高代码的可移植性,使其能适配不同架构的计算机。
(5)简化类型声明
C 语言有些类型声明相当复杂,比如下面这个。
char (*(*x(void))[5])(void);
typedef 可以简化复杂的类型声明,使其更容易理解。
首先,最外面一层起一个类型别名:
typedef char (*Func)(void);
Func (*x(void))[5];
这个看起来还是有点复杂,就为里面一层也定义一个别名:
typedef char (*Func)(void);
typedef Func Arr[5];
Arr* x(void);
上面代码就比较容易解读了。
x
是一个函数,返回一个指向 Arr 类型的指针。Arr
是一个数组,有5个成员,每个成员是Func
类型。Func
是一个函数指针,指向一个无参数、返回字符值的函数。