typedef的使用详解

注:虽然typedef的有些用法在目前的语言中不怎么使用了,但了解它们可以使我们在看一下早期代码书籍时不至于不知道写的是什么。

在旧的C代码中(未考古到底是哪个版本),声明struct新对象时,必须要带上struct,即:struct 结构名 对象名;但C++中,可直接写:结构名 对象名

struct Point {
    int x, y;
};
struct Point p1;//旧的C语言写法
Point p1;//C++中的写法

struct Point {
    int x, y;
}p1;//此处p1是结构类型struct Point的一个对象

typedef struct {
    int x, y;
}POINT;//此处定义了一个匿名的数据结构,而这个数据结构的别名为POINT
POINT p1;//此句代码等价于:struct Point p1;

typedef struct Point {
    int x, y;
}POINT;//此处POINT是结构类型struct Point的一个别名
POINT p1;//此句代码等价于:struct Point p1;
/*上面这段程序实际上完成了两个操作*/
//操作一:定义一个新的结构类型struct Point
struct Point {
    double x, y, z;
};
//操作二:使用typedef为新的结构起了一个别名,叫POINT
typedef struct Point POINT;
//完成上面两步后,就可以像int那样直接使用POINT来定义变量
POINT p1;

typedef struct tagNode {
    char* pItem;
    pNode pNext;//ERROR:在结构体类型本身还没建立完成时,编译器不认识pNode
    struct tagNode* pNext;//OK
} *pNode;//pNode是结构体struct tagNode的别名

typedef可以定义一个别名(可以理解为人的绰号)用来替代基本类型、数组类型、指针类型、用户自定义的结构型、共用型、枚举型,等类型的名称;这个别名可以指明此类型在代码中的作用(例如:用int值来表示状态),或者纯粹是因为数据类型名字太长写起来麻烦

typedef int status;//将int重命名为status是为了告诉我们:该int类型的值表示的是一个状态值
#define TRUE 1
#define FALSE 2

typedef的四种用法:

1、为基本数据类型定义新的类型名

1)定义与平台无关的类型

typedef long double REAL;//定义一个叫REAL的浮点型,表示最高精度的类型
typedef double REAL;//平台不支持long double时可改写为该种形式
typedef float REAL;//平台不支持double时可改写为该种形式

2)跨平台移植程序时,只需修改typedef的定义即可;标准库中广泛地使用了这个技巧

//size_t 在 VC++2010 的 crtdefs.h 文件中的定义如下所示
#ifndef _SIZE_T_DEFINED
#ifdef _WIN64
typedef unsigned _int64 size_t;
#else
typedef _W64 unsigned int size_t;
#endif // _WIN64
#define _SIZE_T_DEFINED
#endif // !_SIZE_T_DEFINED

2、为自定义数据类型(结构体、共用体和枚举类型)定义简洁的类型名称

typedef struct tagPoint Point;//为结构类型struct tagPoint定义了新的别名Point
Point p1 = { 100,100,0 };
Point p2;

3、为数组定义简洁的类型名称

typedef int INT_ARRAY_100[100];
INT_ARRAY_100 arr;

4、为指针定义简洁的名称

int* (*a[5])(int, char*);           //原声明
typedef int* (*pFun)(int, char*);   //变量名为a,直接用一个新别名pFun替换a
pFun a[5];                          //原声明最简化版

void (*b[10]) (void (*)());         //原声明
typedef void (*pFunParam)();        //变量名为b,先替换右边部分括号里的,pFunParam为别名一
typedef void (*pFunx)(pFunParam);   //再替换左边的变量b,pFunx为别名二
pFunx b[10];                        //原声明最简化版

doube(*)() (*e)[9];                 //原声明
typedef double(*pFuny)();           //变量名为e,先替换左边部分,pFuny为别名一
typedef pFuny(*pFunParamy)[9];      //再替换右边的变量e,pFunParamy为别名二
pFunParamy e;                       //原声明最简化版

定义结构体类型的详解:

理解复杂声明可用的“右左法则”:

        从变量名看起,先往右,再往左,碰到一个圆括号就调转阅读的方向;括号内分析完就跳出括号,还是按先右后左的顺序,如此循环,直到整个声明分析完

1)int (*func)(int *p);     

首先找到变量名func,外面有一对圆括号,而且左边是一个*号,这说明func是一个指针。然后跳出这个圆括号,先看右边,又遇到圆括号,这说明 (*func)是一个函数;所以func是一个指向这类函数的指针,即函数指针;这类函数具有int*类型的形参返回值类型是int。

2)int (*func[5])(int *);

func 右边是一个[]运算符,说明func是具有5个元素的数组;func的左边有一个*,说明func的元素是指针(注意这里的*不是修饰func,而是修饰 func[5]的,原因是[]运算符优先级比*高,func先跟[]结合)。跳出这个括号,看右边,又遇到圆括号,说明func数组的元素是函数类型的指 针,它指向的函数具有int*类型的形参,返回值类型为int。

2个模式:

type (*)(....) 函数指针

type (*)[] 数组指针

使用typedef的两个陷阱 

陷阱一:

“const PCHAR”中的 const 给予了整个指针本身常量性,也就是形成了常量指针“char* const(一个指向char的常量指针)”。即它实际上相当于“char* const”,而不是“const char*(指向常量 char 的指针)”——无论什么时候,只要为指针声明 typedef,那么就应该在最终的 typedef 名称中加一个 const,以使得该指针本身是常量

typedef char* PCHAR;
int strcmp(const PCHAR,const PCHAR);

陷阱二:

虽然 typedef 并不真正影响对象的存储特性,但在语法上它还是一个存储类的关键字,就像 auto、extern、static 和 register 等关键字一样;不能声明多个存储类关键字,由于 typedef 已经占据了存储类关键字的位置,因此,在 typedef 声明中就不能够再使用 static 或任何其他存储类关键字

typedef static int INT_STATIC;
//不能声明多个存储类关键字,故在typedef声明中,不能再使用static或其他存储类关键字

附录

typedef struct QNode{
    QElemType data; //数据域 
    struct QNode *next; //指针域 
}QNode,*QueuePtr;

//QNode,*QueuePtr可以这样来理解
typedef struct QNode Qnode    //QNode 的对象都是结构体
typedef struct QNode *QueuePtr    //QueuePtr 的对象都是结构体指针
//类似的例子
typedef struct int ElemType    //定义新的整型变量 ElemType,即ElemType = int
typedef struct int* ElemTypePtr    //定义新的指向整型变量的指针 ElemTypePtr,即ElemTypePtr = int*

你可能感兴趣的:(数据结构,链表)