【正确答案】
【答案解析】typedef与define都是替一个对象取一个别名,以此来增强程序的可读性,但是它们在使用和作用上也存在着以下几个方面的不同:
1)原理不同。#define是C语言中定义的语法,它是预处理指令,在预处理时进行简单而机械的字符串替换,不做正确性检查,不管含义是否正确照样带入,只有在编译已被展开的源程序时才会发现可能的错误并报错。
例如,#define PI 3.1415926,当程序中执行area=PI*r*r语句时,PI会被替换为3.1415926,于是该语句被替换为area=3.1415926*r*r。如果把#define语句中的数字9写成了g,预处理也照样带入,而不去检查其是否合理、合法。
typedef是关键字,它在编译时处理,所以typedef有类型检查的功能。它在自己的作用域内给一个已经存在的类型一个别名,但是不能在一个函数定义里面使用标识符typedef。例如,typedef int INTEGER,这以后就可用INTEGER来代替int作整型变量的类型说明了,如:
INTEGER a,b;
用typedef定义数组、指针、结构等类型将带来很大的方便,不仅使程序书写简单而且使意义更为明确,因而增强了可读性。例如:
typedef int a[10];
表示a是整型数组类型,数组长度为10。然后就可用a说明变量,如a s1,s2;完全等效于int s1[10],s2[10]。同理,typedef void(*p)(void)表示p是一种指向void型的指针类型。
2)功能不同。typedef用来定义类型的别名,这些类型不只包含内部类型(int、char等),还包括自定义类型(如struct),可以起到使类型易于记忆的功能。
例如:typedef int(*PF)(const char*,const char*);
定义一个指向函数的指针的数据类型PF,其中函数返回值为int,参数为const char*。typedef还有另外一个重要的用途,那就是定义机器无关的类型。例如,可以定义一个叫REAL的浮点类型,在目标机器上它可以获得最高的精度:typedef long double REAL,在不支持long double的机器上,该typedef看起来会是下面这样:typedef double REAL,在double都不支持的机器上,该typedef看起来会是这样:typedef float REAL。
#define不只是可以为类型取别名,还可以定义常量、变量、编译开关等。
3)作用域不同。#define没有作用域的限制,只要是之前预定义过的宏,在以后的程序中都可以使用,而typedef有自己的作用域。
程序示例如下:
void fun()
{
#define A int
}
void gun()
{
∥在这里也可以使用A,因为宏替换没有作用域,但如果上面用的是typedef,那这里就不能用
∥A,不过一般不在函数内使用typedef
}
4)对指针的操作不同。两者修饰指针类型时,作用不同。
#define INTPTR1 int*
typedef int* INTPTR2;
INTPTR1 p1,p2;
INTPTR2 p3,p4;
INTPTR1 p1,p2和INTPTR2 p3,p4这两句的效果截然不同的。INTPTR1 p1,p2进行字符串替换后变成int* p1,p2,要表达的意义是声明一个指针变量p1和一个整型变量p2。而INTPTR2 p3,p4,由于INTPTR2是具有含义的,告诉我们是一个指向整型数据的指针,那么p3和p4都为指针变量,这句相当于int* p1,*p2。从这里可以看出,进行宏替换是不含任何意义的替换,仅仅为字符串替换;而用typedef为一种数据类型起的别名是带有一定含义的。
程序示例如下:
#define INTPTR1 int*
typedef int* INTPTR2;
int a=1;
int b=2;
int c=3;
const INTPTR1 p1=&a;
const INTPTR2 p2=&b;
INTPTR2 const p3=&c;
上述代码中,const INTPTR1 p1表示p1是一个常量指针,即不可以通过p1去修改p1指向的内容,但是p1可以指向其他内容。而对于const INTPTR2 p2,由于INTPTR2表示是一个指针类型,因此用const去限定,表示封锁了这个指针类型,因此p2是一个指针常量,不可使p2再指向其他的内容,但可以通过p2修改其当前指向的内容。INTPTR2 const p3同样声明的是一个指针常量。