10.5 #define和typedef的本质区别
在讲解#define和typedef的本质区别之前,先来简单认识#define和typedef。#define在前面已经做了相应的介绍,是一个预处理指令。而typedef并不是一个预处理指令,通常用于为C语言中的标识符或关键字取“别名”,相应的过程是在编译的过程中进行的。
接下来通过代码来了解#define和typedef有什么样的本质区别,以及分别如何使用,先来看下面的代码。
include<stdio.h>
include<stdlib.h>
define INT int
typedef short SHORT;
int main(void)
{
INT a=2;
SHORT b=9;
printf("a=%d\tb=%d\n",a,b);
return 0;
}
运行结果:
a=2 b=9
分析上面的代码,用#define和typedef分别为int和short取了一个别名,两者在这里有着相同的效果,但是建议采用typedef,因为如果定义稍微复杂点的别名,用#define可能会出现问题,例如:
include<stdio.h>
include<stdlib.h>
define PINT int*
typedef short*PSHORT;
int main(void)
{
int a=4;
short b=9;
PINT pa1,pa2;
PSHORT pb1,pb2;
pa1=&a;
pa2=pa1;
pb1=&b;
pb2=pb1;
printf("pa1=%d\tpa2=%d\n",pa1,pa2);
printf("pb1=%d\tpb2=%d\n",pb1,pb2);
return 0;
}
先分析一下上面的代码,我们为int指针和short型指针分别取了别名。在代码中定义了int型变量a和short型变量b,看接下来的代码,本意是定义int指针pa1和pa2,short指针pb1和pb2,它们分别指向变量a和变量b,但是在编译时会出现如下错误:
error C2440:'=':cannot convert from'int*'to'int'
为什么会发生这样的错误呢?我们先进行宏扩展,将代码中的“PINT pa1,pa2;”扩展为“int*pa1,pa2;”,这时就能清楚地发现定义的pa2并不是一个指针,而是一个普通的整型变量,所以当采用整型指针的方式来使用它时就会出现上面的错误了。需要注意的是,通过typedef所取的别名并不是像宏一样只进行简单地替换,这样定义的别名作用于其后出现的所有变量。因此要在代码中取别名,建议采用typedef来实现,以防出现类似的错误。再来看下面的代码。
include<stdio.h>
include<stdlib.h>
typedef int arr[4];
int main(void)
{
arr b={1,2,3,4},c={1,2,3,4};
int i;
for(i=0;i<4;i++)
printf("b[%d]=%d\tc[%d]=%d\n",i,b[i],i,c[i]);
return 0;
}
运行结果:
b[0]=1 c[0]=1
b[1]=2 c[1]=2
b[2]=3 c[2]=3
b[3]=4 c[3]=4
分析上面的代码,用typedef为int arr[4]取了一个别名arr。这时arr就是int[4]类型,因此接下来在代码中定义的arr b,c其实就是int b[4]和int c[4]。由此可以发现,通过typedef可以使代码更加简洁,而且也更加符合我们对类型的理解。接下来再看看typedef在函数指针中的使用,代码如下:
include<stdio.h>
include<stdlib.h>
typedef int(*pfun)(int n);
int power(int n)
{
int pow,i;
pow=1;
for(i=0;i<n;i++)
pow*=2;
return pow;
}
int main(void)
{
pfun pwer;
pwer=power;
printf("2的%d次方为:%d\n",3,pwer(3));
return 0;
}
运行结果:
2的3次方为:8
分析上面的代码,通过typedef为函数指针int(pfun)(int n)取了一个别名pfun,所以接下来在main函数中通过pfun定义的变量pwer实为int(pwer)(int n),由此可见,通过typedef为函数指针取别名可以大大简化和美观代码。接下来看typedef在为结构体取别名时的使用。
include<stdio.h>
include<stdlib.h>
typedef struct stu
{
char name[10];
char nu[10];
int score;
}stu_inf;
int main(void)
{
stu_inf sta={"杭萌","20336545",256};
printf("sta.name:%s\tsta.nu:%s\tsta.score:%d\n",sta.name,sta.nu,sta.score);
struct stu stb={"蒙蒙","20336546",356};
printf("stb.name:%s\tstb.nu:%s\tstb.score:%d\n",stb.name,stb.nu,stb.score);
return 0;
}
运行结果:
sta.name:杭萌sta.nu:20336545 sta.score:256
stb.name:蒙蒙stb.nu:20336546 stb.score:356
分析上面的代码,定义了一个表示学生的简单结构体信息,在定义结构体的时候,采用typedef为结构体取了一个别名stu_inf,所以接下来在需要定义结构体类型的变量时,可以采用结构体的别名来定义,与采用struct stu的方式定义的效果是完全一致的。通过上面的结果可以发现,通过typedef为结构体定义别名之后,在很大程度上简化了代码。