当前位置:文档之家› typedef使用详解

typedef使用详解

typedef使用详解1.再论typedef1.1、如何轻松理解和应用typedef?typedef用最简单的话去诠释他,那么就是给类型取别名。

但是牠并没有你想象的那么简单!举例:typedef int size;//那么int就有一个别名叫size了,以后size就和int这个类型是一样的用法了。

看到这里,如果你仅仅认为typedef不过如此,不就是把第一个参数(类型名),等同于第二个参数,这么简单。

那你可能就会陷入困境。

比如看下面这个例子: typedef char Line[81]; 你能说Line[81]就是char的别名吗?这显然不对。

它真正的含义是:Line类型即代表了具有81个元素的字符数组。

那么Line t;就等同于char t[81];看到这里读者是否晕了?我们尝试把它放在一起看看。

typedef int size; //typedef行int i; //原型行size i; //应用行同理:typedef char Line[81]; //typedef行char t[81]; //原型行Line t; //应用行再举一个函数指针的例子:typedef int (*fun_ptr)(int,int); //typedef行int (*fp)(int,int); //原型行fun_ptr fp; //应用行以上3个例子都有以下几个共同点:1、“typedef行”和“原型行”相比,“typedef行”仅仅多个typedef而已。

就函数指针的例子来说,其次,“typedef行”和“原型行”的根本区别在于:fun_ptr是类的别名,fp是该类的变量。

2、“原型行”和“应用行”,它们的编译结果是一样的。

就函数指针的例子来说,他们都是创建了一个类型为int (*)(int,int)的函数指针fp。

只是fun_ptr fp(应用行)比int (*fp)(int,int)(原型行)这种形式更加简洁,便与书写和理解。

形式越复杂typedef 的优势就越明显。

Typedef的定义应用和理解应该是一步到位的。

定义过程:只要我们能写出原型行,就能直接写出typedef行。

应为形式上只差一个typedef。

如:我们写出原型:char t[81],那么加上一个typedef就能得到我们想要的定义,当然可以修改下类名,如:typedef char T[81]。

应用过程:T t;其中T是之前定义的类型,t是通过该类型定义的变量。

理解过程:如何理解“T t;”要想理解“T t;”就找到与之对应的“原型行”,但是“原型行”一般在程序中是不会出现,所以只能先找到“typedef行”,在通过“typedef行”推出“原型行”(推的过程就是去掉typedef而已)。

“T t;”的“typedef行”为typedef char T[81],所以“T t”所表示的“原型行”就是char x[81],而“原型行”和“应用行”(这里“T t;”就是应用行),的含义完全相同。

那么对“T t;”的理解就是对char x[81]的理解。

在“T t”的定义中,T的typedef定义形式为:typedef char T[81];因此T t就等价于:char t[81];所以:typedef char T[81];T t;与直接char t[81];是完全等价的。

小结:当我们看到一个typedef定义时,如:typedef int (*fun_ptr)(int,int)。

我们的大脑里需要做两个条件反射:1、typedef是给类取别名,所以只要是typedef定义的东西都是类型。

所以,看到以上表达式就要意识到fun_ptr是个类型。

2、要理解typedef到底定义了什么,首先去掉typedef,再将typedef 定义的“类型”看成“变量”。

如:将以上表达式就看成:int (*x)(int,int),就能明白该表达是的目的是想定义一个函数指针类型。

注意事项:typedef在语法上是一个存储类的关键字(如auto、extern、static、register),而变量只能被一种储类的关键字修饰。

如果变量被两种及以上储类的关键字修饰则编译报错:typedef static int a;//错误示范错误信息为:multiple storage classes in declaration specifiers。

1.2、typedef与#define宏的区别讲到typedef就不得不提一提#define,以便大家对比学习,将知识点编织成网。

与typedef不同,#define是单纯的替换,替换发生在预编译过程,此时可以把#define的每个参数看成一堆字母,#define 只是将一堆字母用另一堆字符母换。

至于字母的含义分析,在预编译过程之后。

也就是说#define要做的只是傻傻的替换,至于词义的分析不在它的能力范围之内。

替换规则是,#define会将它右边的第一个参数作为替换的结果,将之后的参数(直到换行符)作为替换的目标。

接下来,就对比下typedef与#define:#define dpChar char*typedef char* tpChar;dpChar p1, p2;tpChar p3, p4;这里貌似#define和typedef想干的是同一件事——用一个新的名字替换掉char*。

先不管结果是否一致,先看看形式上有什么不同:#define dpChar char*typedef char* tpChar;首先,#define是没有分号的(当然如果有分号,分号也将成为替换的内容,但这明显不是我们想要的结果)。

而typedef作为语句,必须是有分号的。

其次,他们的参数看上去是反过来的,如char*在#define里是作为第二个参数,而在typedef是作为第一个参数。

有的时候,还真的容易弄反了。

记得有一次,读者在头文件里定义了一个#defin就把顺序弄反了,结果编译报错,愣是看了好久没发现问题。

那么如何解决这个易混淆的地方呢?其实如果读者能回想一下上一节内容这个问题就可以迎刃而解。

当我们用typedef定义类型时,如果去掉typedef,形式上其实是一个再正常不过的定义变量的语句。

如typedef char* tpChar;去掉typedef之后,就是char* tpChar;所以此时char*当然在前面。

所有只要记住顺序上#define和typedef相反就行了,#define是将第一个参数作为替换的结果。

说完了形式的区别,再来看看结果是否一致:dpChar p1, p2;tpChar p3, p4;dpChar是#define定义的,按照替换原则,替换的结果为:char* p1, p2;再进行语法分析可知结果为:char* p1;和char p2。

此时p1是char*类型p2是char类型。

而tpChar是typedef给char*取的别名,此时定义出的p3和p4的类型都是char*。

所以想一次性定义多个指针变量,记得用typedef。

1.3、typedef与struct结构体在使用时都是先定义结构体类型,再用结构体类型去定义变量。

如struct node {}这样就定义了一个node的结构体类型。

在申请node的变量时,必须带上struct:struct node n;如果配合typedef,有如下几种用法:1、在利用结构体类型申请变量时就可以省略掉struct这个关键字:typedef struct node{} Node;//给struct node{}类型取别名Node n;//利用结构体类型申请变量2、使用typedef一次定义2个类型,分别是结构体变量类型,和结构体变量指针类型。

typedef struct node{} Node, *pNode;这句话可以拆分成两句理解: typedef 类型Node;和typedef 类型* pNode;其中Node为结构体类型,pNode是结构体指针类型。

1.4、 typedef与const(1)typedef int *PINT; const PINT p2; 相当于是int *const p2;(2)typedef int *PINT; PINT const p2; 相当于是int *const p2;(3)如果确实想得到const int *p;这种效果,只能typedef const int *CPINT;CPINT p1;1.5、使用typedef的重要意义使用typedef的原因主要有两个:1、简化类型,让程序更易理解和书写。

2、创造平台无关类型,便与移植。

至于简化模型这点,从“如何轻松理解和应用typedef?”这节中的第三例子应该可以体会到了。

这里再来举个例子来体会下:不采用typedef的情况:void (*a[10]) (void (*)());采用typedef的情况:typedef void (*pFun)(pFunParam);pFun a[10];这里重点说说typedef的第二个重要意义——创造平台无关类型。

比如利用typedef 定义一个浮点类型,名字就叫myMax,myMax必须始终代表该平台的最高精度的浮点类型。

如果程序移植到支持long double的平台上就给long double取别名为myMax,如果程序移植到最多支持float的精度的平台上就给float取别名为myMax。

如果仅仅采用系统提供的原生类型,而不采用typedef取别名的方式,当程序移植时,可能面临大量的程序修改工作。

比如,之前用到了long double这个类型,当移植到另一个平台时,这个平台只支持float类型而不支持long double这个类型。

那么你将面临将全部的long double换成float。

而如果,之前将long double取别名为myMax,程序中用的类型都是myMax。

那么我们只需要把typedef long double myMax;更换为typedef float myMax;即可。

相关主题