在现实生活中,信息的概念可能是长度、数量和面积等。在C语言中,信息被抽象为int、float和double等基本数据类型。从基本数据类型名称上,不能看出其所代表的物理属性,并且int、float和double为系统关键字,不可以修改。为了解决用户自定义数据类型名称的需求,C 语言中引入typedef,可以为数据类型创建别名,从而丰富数据类型所包含的属性信息。
一般形式:
typedef 类型名称 类型别名
说明:
1.typedef为系统关键字,“类型名称”为已知数据类型名称,包括基本数据类型(如char、int)、UDT(如数组、struct);
2. typedef为数据类型创建别名,而不是创建新的数据类型,可以对任何类型进行typedef声明。typedef是一种彻底的“封装”类型,在声明它之后就不能再往里面
3.习惯上常把typedef声明的类型名用大写字母表示
增加别的东西了;
typedef double LENGTH; typedef unsigned int COUNT;创建了别名之后,可像基本数据类型那样定义变量
例如:
typedef unsigned int COUNT; unsigned int b; COUNT c;
例子:
typedef unsigned int COUNT; typedef double AREA; COUNT age; AREA s;
应用的主要目的:
首先是丰富数据类型中包含的属性信息,
其次是为了系统移植的需要,稍后详细描述
例子:
其中结构体 struct Point 为新的数据类型,在定义变量的时候均要有保留字struct,而不能像int和double那样直接使用Point来定义变量struct Point { double x; double y; double z; }; struct Point oPoint1={100,100,0}; struct Point oPoint2;
如果经过如下的修改:
typedef struct tagPoint { double x; double y; double z; } Point;使用typedef之后,定义变量简化为Point oPoint;
例如:
在C语言中,可以将长度为10的整型数组看作为一个数据类型,再利用typedef为其重定义一个新的名称,可以更加简洁形式定义此种类型的变量,具体的处理方式如下:int a[10], b[10], c[10];
其中INT_ARRAY_10 和 INT_ARRAY_20为新的类型名,10和20 为数组的长度。a,b,c,d 均是长度为 10 的整型数组,e 是长度为 20 的整型数组。typedef int INT_ARRAY_10[10]; typedef int INT_ARRAY_20[20]; INT_ARRAY_10 a,b,c,d; INT_ARRAY_20 e;
首先,为数据指针定义新的名称,在连续几个变量的声明中,用typedef定义的类型能够保证声明中的所有变量均为同一种类型如下:
typedef char * STRING; STRING csName = “Jhon”;其次,也可以为函数指针定义新的名称
typedef int (*MyFUN)(int a,int b); int Max(int a,int b); MyFUN pMyFun; pMyFun = Max;其中 MyFUN 代表 int XFunction(int a,intb)类型的函数指针的新名称。
用途一:
定义一种类型的别名,而不只是简单的宏替换,可以用作同时声明指针型的多个对象。
typedef char * PCHAR; PCHAR pa, pb;//同时声明了两个指向字符变量的指针在大量使用指针的地方typedef更加方便
用途二:
用 typedef 来定义与平台无关的类型。
typedef long double REAL;
在不支持 long double 的平台二上,改为:
typedef double REAL;
当跨平台时,只要改下typedef本身就行,不用对其他源码做任何修改,标准库就广泛使用了这个技巧,比如size_t。另外,因为 typedef是定义了一种类型的新别名,不是简单的字符串替换,所以它比宏来得稳健。
用途三:
为复杂的声明定义一个新的简单的别名,举例:
1. 原声明:int *(*a[5])(int, char*);
变量名为 a,直接用一个新别名 pFun 替换 a
typedef int *(*pFun)(int, char*);
原声明的最简化版:
理解复杂声明可用的“右左法则”:从变量名看起,先往右,再往左,碰到一个圆括号就调转阅读的方向;括号内分析完就跳出括号,还是按先右后左的顺序,如此循环,直到整个声明分析完。举例:pFun a[5];
分析:
int (*func)(int *p);
先找到变量名 func,外面有一对圆括号,而且左边是一个*号,这说明 func 是一个指针;然后跳出这个圆括号,先看右边,又遇到园括号,这说明 (*func)是一个函数,所以 func 是一个指向这类函数的指针,即函数指针,这类函数具有 int*类型的形参,返回值类型是 int。
分析:
int (*func[5])(int *);
例子:陷阱一:
记住,typedef 是定义了一种类型的新别名,不同于宏,它不是简单的字符串替换。可以看作是一种彻底的“封装”
typedef char * PSTR; #define DEFCHAR char* .... char string[10] = "abcde"; const DEFCHAR p1 = string;//字符首地址 const PSTR p2 = string; p1++; //ok p2++; //error printf("%c %c\n",*p1,*p2);
通过编译运行可知:p2++出错。
分析:
这个问题再一次提醒我们:typedef和#define不同,它不是简单的文本替换。
上述代码中“第一个const”修饰的是“p1指向的对象,不能通过*p1改变对象的内容”;“第二个const”修饰的是“p2本身,p2是常量”。const pStr p2并不等于const char * p2。const PSTR p2和const long x本质上没有区别,认为都是对变量进行只读限制;为了容易理解,可以把PSTR当作“基本类型”来处理,只不过此处的基本类型是我们自己定义的而不是系统固有类型。因此,const PSTR p2的含义是:限定数据类型为char *的变量p2为只读,因此p2++错误。
陷阱二:
typedef 在语法上是一个存储类的关键字(如 auto、extern、static、register),但它并不真正影响对象的存储特性,如:
typedef static int INT2; //error,指定了一个以上的存储类
1)#define是预处理指令,主要定义常量,此常量可以为任何的字符及其组合;在编译预处理时进行简单的替换,不作正确性检查,不关含义是否正确照样带入,只有在编译已被展开的源程序时才会发现可能的错误并报错。例如:
#define PI 3.1415926
程序中的:area=PI*r*r 会替换为 3.1415926*r*r ;如果你把#define 语句中的数字9写成字母g预处理也照样带入。
2)typedef是在编译时处理的。它在自己的作用域内给一个已经存在的类型一个别名。
3)#define在预处理时进行简单的替换,而 typedef不是简单替换 。例如:
#define int_ptr int * int_ptr a, b; //相当于int * a, b;只是简单的宏替换 .... typedef int* int_ptr; int_ptr a, b; //a, b 都是指向int的指针,
4)也许您已经注意到#define不是语句,不要在行末加分号,否则会连分号一块置换;而typedef是声明语句,有分号。
详解typedef用法及define的区别,布布扣,bubuko.com
原文:http://blog.csdn.net/xiao3404/article/details/22382093