除了可以直接使用 C 提供的标准类型名(如 int,char,float, double 和 long 等)和程序编写者自己声明的结构体、共用体、枚举类型外,还可以用 typedef 指定新的类型名来代替已有的类型名。有以下两种情况
目录
一、简单地用一个新的类型名代替原有的类型名
例如:
typedef int Integer; //指定用Integer为类型名,作用与int相同
typedef float Real; //指定用Real为类型名,作用与float相同
指定用 Integer 代表 int 类型,Real 代表 float。这样,以下两行等价:
int i,j; float a,b;
Integer i,j; Real a,b;
这样可以使熟悉 FORTRAN 的人能用 Integer 和 Real 定义变量,以适应他们的习惯。
又如在一个程序中,用一个整型变量来计数,则可以命名 Count 为新的类型名 代表 int 类型:
typedef int Count; //指定Count代表int
Count i,j; //用Count定义变量i和j,相当于int i,j;
将变量 i,j 定义为 Count 类型,而 Count 等价于 int,因此 i,j 是整型。在程序中将 i,j 定义为 Count 类型,可以使人更一目了然地知道它们是用于计数的。
二、命名一个简单的类型名代替复杂的类型表示方法
从前面已知,除了简单的类型(如 int,float 等)、C 程序中还会用到许多看起来比较复杂的类型,包括结构体类型、共用体类型、枚举类型、指针类型,数组类型等,如:
float* []; //指针数组
float(*)[5]; //指向5个元素的一维数组的指针
double* (double*); //定义函数, 函数的参数是double* 型数据,
//即指向double数据的指针, 函数返回值也是指向double数据的指针
double (*)(); //指向函数的指针, 函数返回值类型为double
int* (*(*)[10];)(void); //指向包含10个元素的一维数组的指针, 数组元素的类型为函数指针
//(函数的地址), 函数没有参数, 函数返回值是int指针
有些类型形式复杂,难以理解﹐容易写错。C允许程序设计者用一个简单的名字代替复杂的类型形式。例如:
(1)命名一个新的类型名代表结构体类型:
typedef struct
{
int month;
int day;
int year;
} Date;
以上声明了一个新类型名Date,代表上面的一个结构体类型。然后可以用新的类型名 Date 去定义变量,如:
Date birthday; //定义结构体类型变量 birthday,不要写成struct Date birthday;
Date* p; //定义结构体指针变量p,指向此结构体类型数据
(2)命名一个新的类型名代表数组类型
typedef int Num[100]; //声明Num为整型数组类型名
Num a; //定义a为整型数组名,它有100个元素
(3)命名一个新的类型名代表指针类型
typedef char* String; //声明String为字符指针类型
String p, s[10]; //定义p为字符指针变量,s为字符指针数组
(4)命名一个新的类型名代表指向函数的指针类型
typedef int (*Pointer)(); //声明Pointer为指向函数的指针类型,该函数返回整型值
Pointer pl, p2; //p1,p2为Pointer类型的指针变量
归纳起来,声明一个新的类型名的方法是:
①先按定义变量的方法写出定义体( 如:int i; )。
②将变量名换成新类型名( 例如:将 i 换成 Count )。
③在最前面加 typedef ( 例如:typedef int Count )。
④然后可以用新类型名去定义变量。
简单地说,就是按定义变量的方式,把变量名换上新类型名,并且在最前面加 typedef,就声明了新类型名代表原来的类型。
以定义上述的数组类型为例来说明:
①先按定义数组变量形式书写:int a[100]。
②将变量名a换成自己命名的类型名:int Num[100]。
③在前面加上 typedef,得到 typedef int Num[100]。
④用来定义变量:Num a; 相当于定义了:int a[100];
同样,对字符指针类型,也是:
char* p; //定义变量p的方式
char* String; //用新类型名String 取代变量名p
typedef char* String; //加typedef
String p; //用新类型名String定义变量,相当char* p;
习惯上,常把用 typedef 声明的类型名的第 1 个字母用大写表示,以便与系统提供的标准类型标识符相区别。
三、拓展
(1)以上的方法实际上是为特定的类型指定了一个同义字(synonyms)。
例如:
typedef int Num[100];
Num a; //Num是int[100]的同义词,代表有100个元素的整型数组
typedef int (*Pointer)();
Pointer pl; //Pointer是int(*)()的同义词。代表指向函数的指针类型,函数值为整型
用 typedef 声明的新类型称为原有类型的 typedef 名称。
(2)用 typedef 只是对已经存在的类型指定一个新的类型名,而没有创造新的类型。例如,前面声明的整型类型 Count,它无非是对 int 型另给一个新名字。又如:
typedef int Num[10];
无非是把原来用 “ int a[10]; ” 定义的数组类型用一个新的名字 Num 表示。无论用哪种方式定义变量,效果都是一样的。
(3)用 typede f声明数组类型、指针类型、结构体类型、共用体类型、枚举类型等,使得编程更加方便。例如定义数组,原来是用
int a[10], b[10], c[10], d[10];
由于都是一维数组,大小也相同,可以先将此数组类型命名为一个新的名字Arr,即:
typedef int Arr[10];
然后用 Arr 去定义数组变量:
Arr a, b, c, d; //定义5个一维整型数组,各含10个元素
Arr 为数组类型,它包含 10 个元素。因此,a,b,c,d 都被定义为一维数组,各含 10 个元素。
可以看到,用 typedef 可以将数组类型和数组变量分离开来,利用数组类型可以定义多个数组变量。同样可以定义字符串类型、指针类型等。
(4) typedef 与 #define 表面上有相似之处,例如:
typedef int Count;
和
# define Count int;
从表面看它们的作用都是用 Count 代表 int。但事实上,它们二者是不同的。#define 是在预编译时处理的,它只能作简单的字符串替换,而 typedef 是在编译阶段处理的。实际上它并不是作简单的字符串替换,例如:
typedef int Num[10];
Num a;
并不是用 “ Num[10] ” 去代替 “ int ”,而是采用如同定义变量的方法那样先生成一个类型名(就是前面介绍过的将原来的变量名换成类型名),然后用它去定义变量。
(5)当不同源文件中用到同一类型数据(尤其是像数组、指针、结构体、共用体等类型数据)时,常用 typedef 声明一些数据类型。可以把所有的 typedef 名称声明单独放在一个头文件中,然后在需要用到它们的文件中用 #include 指令把它们包含到文件中。这样编程者就不需要在各文件中自己定义 typedef 名称了。
(6)使用 typedef 名称有利于程序的通用与移植。有时程序会依赖于硬件特性,用 typedef 类型就便于移植。例如,有的计算机系统 int 型数据占用两个字节,数值范围为-32768~32767,而另外一些机器则以 4 个字节存放一个整数,数值范围为 ±21亿。
如果把一个 C 程序从一个以 4 个字节存放整数的计算机系统移植到以 2 个字节存放整数的系统,按一般办法需要将定义变量中的每个 int 改为 long,将 “ int a,b,c; ” 改为 “ long a,b,c;”,如果程序中有多处用 int 定义变量,则要改动多处。现可以用一个 Integer 来代替 int :
typedef int Integer;
在程序中所有整型变量都用 Integer 定义。在移植时只须改动 typedef 定义体即可:
typedef long Integer;