一、typedef的用法在C/C++语言中,typedef常用来定义一个标识符和一个关键字的别名,是关键字的一部分语言编译过程,但实际上并不分配内存空间,如:typedefintINT;typedef(int*)pINT;typedefunsignedintuint32_ttypedef可以增强程序的可读性和标识符的灵活性,但也有“不直观”等缺点。2、#define的用法#define是一个宏定义语句,通常用于定义常量(包括无参和有参),实现那些“表面上看起来和蔼可亲,背后一长串”的宏他们”。它不是在编译过程中进行的,而是在此之前就已经完成了(预处理过程),但是也很难发现潜在的错误和其他代码维护问题,例如:#defineINTint#defineTRUE1#defineAdd(a,b)((a)+(b));#defineLoop_10for(inti=0;i<10;i++)在ScottMeyer的EffectiveC++一书中的第1条中,分析了#define语句,也是一个不错的选择,大家可以参考一下。3、typedef和#define的区别从上面的概念基本可以清楚。typedef只是标识符的一个新名称(只是一个别名)以增加可读性,而#define最初是在C中定义常量。到了C++,const、enum、inline的出现,让它逐渐成为了别名化的利器。有时很容易混淆#define和typedef,应该使用哪一个。比如#defineINTint这样的语句可以用typedef补全,应该用哪一个呢?我提倡使用typedef,因为这个语句在很多早期的C编译器中是不合法的,但是今天的编译器对它进行了扩展。为了尽可能兼容,一般在#define之后定义“可读”常量和宏语句的一些任务,而typedef则常用于为冗长的类型定义关键字和别名。宏定义只是简单的字符串替换(就地展开),但typedef不是就地展开。它的新命名具有一定的封装性,使新命名的标识符具有更容易定义变量的功能。例如代码:typedef(int*)pINT;和:#definepINT2int*;有同样的效果吗?这不一样!看实践中的区别:pINTa,b;与int*a具有相同的效果;诠释*b;表示定义了两个整型指针变量。pINT2a、b的作用;与int*a,b相同;表示定义了一个整型指针变量a和一个整型变量b。四、typedef的使用使用一:定义一个类型的别名,而不是简单的宏替换。可用于同时声明多个指针类型的对象。例如:char*pa,pb;//这多半不符合我们的意图,它只是声明了一个指向字符变量的指针,和一个字符变量;以下作品:typedefchar*PCHAR;PCHARpa,pb;//同时声明了两个指向字符变量的指针。下面的(代码)方式虽然也是可行的,但是使用typedef的形式比较不直观,尤其是需要大量指针的地方,typedef的方式更方便。字符*pa,*pb;用途2:用在旧的C代码中(具体年代没查),帮助struct。前面的代码中,在声明一个新的struct对象时,必须带上struct,即形式为:struct结构名对象名,如:structtagPOINT1{intx;诠释是;};结构标记点1p1;而在C++中,则可以直接写:结构名对象名,即:tagPOINT1p1;估计有人觉得经常多写一个struct太麻烦了,于是发明了:typedefstructtagPOINT{intx;inty;}POINT;POINTp1;//这样就比原来的方法少写了一个struct,比较麻烦,尤其是大批量使用的时候。或许,在C++中,typedef的用处不是很大,但了解它对于掌握老代码还是有帮助的。毕竟,我们可能会遇到项目早期遗留下来的代码,这很有帮助。使用三:使用typedef定义平台无关类型。例如,定义一个名为REAL的浮点类型。在目标平台1上,让它表示精度最高的类型:typedeflongdoubleREAL;在不支持longdouble的平台2,改为:typedefdoubleREAL;对于不支持的平台,改为:typedeffloatREAL;也就是说,跨平台时,只需要改变typedef本身,而不需要对其他源代码做任何改动。标准库广泛使用了这种技术,例如size_t。另外,因为typedef是定义类型的新别名,而不是简单的字符串替换,所以它比宏更健壮(尽管有时可以使用宏来完成上述目的)。用途4:为复杂语句定义一个新的简单别名。方法是:逐步用原声明中的别名替换部分复杂声明,以此类推,最后留下需要替换的变量名部分,得到最简化的原始声明版本。以下列情况为例。1、原语句:int*(*a[5])(int,char*);变量名为a,只需将a替换为新的别名pFun:typedefint*(*pFun)(int,char*);原始语句的简化版本:pFuna[5];2、原语句:void(*b[10])(void(*)());变量名为b,先替换右边的括号,pFunParam为别名1:typedefvoid(*pFunParam)();然后替换左边的变量b,pFunx是别名2:typedefvoid(*pFunx)(pFunParam);原始语句的简化版本:pFunxb[10];3原始语句:doube(*)()(*e)[9];变量名为e,先替换左边部分,pFuny为别名1:typedefdouble(*pFuny)();然后替换右边的变量e,pFunParamy为别名2,typedefpFuny(*pFunParamy)[9];原始声明的最简化版本:pFunParamye;可用于理解复杂声明的“左右规则”:从变量名开始,先向右走,再向左走,遇到括号会反转阅读方向;括号内分析完就会跳出括号,或者按照先右后左的顺序跳出,以此类推,直到分析完整个语句。示例:int(*func)(int*p);首先找到变量名func,外面有一对括号,左边有一个*号,表示func是一个指针;然后跳出括号,先看右边,再遇到括号就说明(*func)是一个函数,所以func是指向这一类函数的指针,也就是函数指针。这种类型的函数有一个int*类型的参数,返回值类型是int。int(*func[5])(int*);func右边是一个[]运算符,表示func是一个有5个元素的数组;func左边有个*,表示func的元素是一个指针(注意这里的*不是修饰func,而是修饰func[5],因为[]运算符的优先级比*,而func则先与[]组合)。跳出括号,向右看,又遇到括号,说明func数组的元素是函数类型的指针,它指向的函数有int*类型的形参,返回值类型是int.还可以记住2个模式:type(*)(....)functionpointertype(*)[]arraypointer五、typedeftraptrap一:记住,typedef是定义类型的新别名,不像宏,它是不是简单的字符串替换。比如先定义:typedefchar*PSTR;然后:intmystrcmp(constPSTR,constPSTR);constPSTR实际上等同于constchar*吗?不,它实际上等同于char*const。原因是const赋予了整个指针本身的常量性,即形成了一个常量指针char*const。总之,记住当const和typedef一起出现时,typedef不是简单的字符串替换。陷阱二:typedef在句法上是一个存储类(如auto、extern、static、register等)的关键字,虽然它并不真正影响对象的存储特性,如:typedefstaticintINT2;//不可行编译会失败并显示“指定了多个存储类”。
