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为结构体定义别名之后,在很大程度上简化了代码。