首先是typedef历史遗留问题,经常看到很多人写结构体就写:
typedef struct _A{int a;int b;}A;
A b;
我就一直很纳闷,为什么不直接写_A b呢?
昨天查资料才知道,原来这个是因为c语言遗留下来的,在C语言中,结构体对象声明必须加关键字struct,所以按C语言语法是:
struct _A b;
大家都知道程序员很讲究效率,编代码也是,能少些一个单词绝不多写,所以用typedef确实是可以少些一个单词。
其实typedef不光可以少些单词,更重要的是代码美观,和避免拙劣代码(这个后面会提到)。
typedef常用方法分为3点:
1:typedef为已经存在的类型定义别名,以增强可读性和避免平台的底层差异。
typedef int size;
size len=strlen(str);
这样类型名在一定程度上起了提示作用。而且可以避免平台的底层实现问题。如某个嵌入式平台没有实现int类型,而是由一个integer或者double。这个是用只需将项目的typedef改一下就可以,整个项目几乎不用动(如果新的类型不引发逻辑错误的话)。
常见的还有定义指针的:如
typedef void* PVOID;//etc
2:定义数组对象
typedef int array[2][2];
array b;
这个时候b就代码int[2][2]了。具体解析在第3点之后讲
3:定义函数指针
typedef int(*pF)(const char*,const char*);
这就定义了pF为一个函数指针。其返回值为int,参数是两个const char*。
由于pF是函数指针,所以可以声明这么一个函数,函数名是Register,函数的参数是一个pF类型的函数指针,返回值也是一个pF类型的函数指针。
pF Register(pF p);
但是如果没有typedef那会怎么样呢?
int(*Register (int(*pF)(const char*,const char*)))(const char*,const char*);
试问人世间愿意看到这样的代码的正常人还有多少?
我来分析一下为什么是这么写的,首先Register的参数列表是( int(*pF)(const char*,const char*) ),最外层括号里面是一个函数指针参数。
然后看函数名左边是*号,说明函数返回一个指针,然后用指针的眼光看待,把函数指针从结构中抽离出来就是int(*)(const char*,const char*)了。
其中2,3方法中牵扯到一个typedef的识别规则,就是“右左法则”。先往又看到一个括号或结尾,然后往往左看一个括号或结尾,重复此过程直到分析结束。
用这个方法分析2,3.先分析2:
先往右看是[2][2]说明array是一个数组,往左看知道他是int类型。这样就知道array代表整型2维数组。
再分析3:
先往又看是括号没说明什么,然后往左看是*,说明pF是指针。然后再忘又看是参数列表,说明是函数指针,再往左看是int就知道他是返回值了。
同时typedef的一些常出的错误:
1:
typedef char* PSTR;
const PSTR a;
此时const PSTR不代表const char*;而是代表char const*;
因为要从本质的理解const用法,const是给某个属性附加上常量属性。所以const PSTR是对字符指针加上不可变的常量属性。
就指针而言不可变是指的其指向不可变。
如果不明白的好:好好看看 const char*和char const*的区别。
2:
typedef在语法上是以存储关键字,所以typedef不能与auto,static,register,extern,mutable连用
如果连用:
typedef static int SINT;
编译器就是报告错误:有一个以上的存储关键字!
还有一些typedef经常与#define进行比较。
typedef比#define更结构化。
#define就是宏替换。而typedef是在语法级别上的代替。
所以一下代码比较:
typedef char* PSTR;
PSTR a,b;
相当于char* a;char *b;
而#define不然;请看
#define PSTR char *
PSTR a,b;
相当于char* a,b;
初学者可不要以为char *a,b;和char *a,char *b;是一回事。
C++基础知识里面有char* a,b;并没有把char* 类型给b,而是只给了char类型。所以char* a,b;中b是char类型而不是char*。
打完收工!
分享自己的心得,是帮助了别人,升华了自己!