首页 > 代码库 > 关于typedef的用法总结

关于typedef的用法总结

typedef 声明,简称typedef,为现有类型创建一个新的名字。比如人们常常使用 typedef 来编写更美观和可读的代码。所谓美观,意指typedef能隐藏笨拙的语法构造以及平台相关的数据类型,从而增强可移植性和以及未来的可维护性。

定义类型别名

定义一种类型的别名,而不只是简单的宏替换。可以用作同时声明指针型的多个对象。

  1. char* pa, pb; // 这多数不符合我们的意图,它只声明了一个指向字符变量的指针,和一个字符变量;
  2. //以下则可行:
  3. typedef char* PCHAR;
  4. PCHAR pa, pb;

typedef 并不创建新的类型。它仅仅为现有类型添加一个同义字。

定义结构体

以前的代码中,声明struct新对象时,必须要带上struct,即形式为: struct 结构名 对象名,如:

  1. struct tagPOINT1
  2. {
  3. int x;
  4. int y;
  5. };
  6. struct tagPOINT1 p1;

而在C++中,则可以直接写:结构名对象名,即:tagPOINT1 p1;

  1. typedef struct tagPOINT
  2. {
  3. int x;
  4. int y;
  5. }POINT;

POINT p1; // 这样就比原来的方式少写了一个struct,比较省事,尤其在大量使用的时候,或许,在C++中,typedef的这种用途不是很大,但是理解了它,对掌握以前的旧代码还是有帮助的。

定义与平台无关的类型

比如定义一个叫 REAL的浮点类型,在目标平台一上,让它表示最高精度的类型为:

typedef long double REAL;

在不支持 long double 的平台上,改为:

typedef double REAL;

在连 double 都不支持的平台上,改为:

typedef float REAL;

也就是说,当跨平台时,只要改下typedef本身就行,不用对其他源码做任何修改。

标准库就广泛使用了这个技巧,比如size_t。另外,因为typedef是定义了一种类型的新别名,不是简单的字符串替换,所以它比宏来得稳健。

定义数组类型

typedef 还可以掩饰符合类型,如指针和数组。

typedef int MyIntArray[100]; //MyIntArray表示一个包含100个整形的数组

那么程序中的

MyIntArray ia; //ia是个包含100个整形的数组

就相当于

int ia[100]; 

应用于指针:

  1. typedef char * pstr; //pstr 是一个指向char的指针哈
  2. int mystrcmp(pstr, pstr); //两个参数可是两个指针

上面讨论的 typedef行为有点像#define宏,用其实际类型替代同义字。不同点是 typedef 在编译时被解释,因此让编译器来应付超越预处理器能力的文本替换。

定义函数指针

typedef void (*FUNCADDR)(int) 

此处FUNCADDR是指向这样一个函数的指针,该函数的返回值为void类型,函数有一个int型的参数。再例如:

  1. void print (int x)
  2. {
  3. printf ("%d\n", x);
  4. }
  5. int main (int argc, char *argv[])
  6. {
  7. FUNCADDR pFunc;
  8. pFunc = print; // 将指针指向print函数
  9. (*pFunc)(25); // 调用函数print
  10. return 0;
  11. }

来,一起看一个更复杂的:

typedef int (*PF) (const char *, const char *);

这个声明引入了 PF 类型作为函数指针的同义字,该函数有两个 const char * 类型的参数以及一个int类型的返回值。如果要使用下列形式的函数声明,那么上述这个 typedef 是不可或缺的:

PF Register(PF pf);

Register() 的参数是一个PF类型的回调函数,返回某个函数的地址,其署名与先前注册的名字相同。做一次深呼吸。下面展示一下如果不用typedef,我们是如何实现这个声明的:

  1. int (*Register (int (*pf)(const char *, const char *)))
  2. (const char *, const char *);

很少有程序员理解它是什么意思,更不用说这种费解的代码所带来的出错风险了。显然,这里使用 typedef 不是一种特权,而是一种必需。

C语言中typedef用法

  1. 基本解释

      typedefC语言的关键字,作用是为一种数据类型定义一个新名字。这里的数据类型包括内部数据类型(int,char等)和自定义的数据类型(struct等)。

在编程中使用typedef目的一般有两个,一个是给变量一个易记且意义明确的新名字,另一个是简化一些比较复杂的类型声明。

至于typedef有什么微妙之处,请你接着看下面对几个问题的具体阐述。

  1. typedef & 结构的问题

当用下面的代码定义一个结构时,编译器报了一个错误,为什么呢?莫非C语言不允许在结构中包含指向它自己的指针吗?请你先猜想一下,然后看下文说明:

  1. typedef struct tagNode
  2. {
  3.  char *pItem;
  4.  pNode pNext;
  5. } *pNode;

答案与分析:

 1. typedef的最简单使用

typedef long byte_4;

给已知数据类型long起个新名字,叫byte_4

  1. typedef与结构结合使用
  1. typedef struct tagMyStruct
  2. {
  3.  int iNum;
  4.  long lLength;
  5. } MyStruct;

这语句实际上完成两个操作:

  1) 定义一个新的结构类型

  1. struct tagMyStruct
  2. {
  3.  int iNum;
  4.  long lLength;
  5. };

分析:tagMyStruct称为tag,即“标签”,实际上是一个临时名字,struct 关键字和tagMyStruct一起,构成了这个结构类型,不论是否有typedef,这个结构都存在。

我们可以用struct tagMyStruct varName来定义变量,但要注意,使用tagMyStruct varName来定义变量是不对的,因为struct 和tagMyStruct合在一起才能表示一个结构类型。

  2) typedef为这个新的结构起了一个名字,叫MyStruct

typedef struct tagMyStruct MyStruct;

因此,MyStruct实际上相当于struct tagMyStruct,我们可以使用MyStruct varName来定义变量。

答案与分析:

C语言当然允许在结构中包含指向它自己的指针,我们可以在建立链表等数据结构的实现上看到无数这样的例子,上述代码的根本问题在于typedef的应用。

根据我们上面的阐述可以知道:新结构建立的过程中遇到了pNext域的声明,类型是pNode,要知道pNode表示的是类型的新名字,那么在类型本身还没有建立完成的时候,这个类型的新名字也还不存在,也就是说这个时候编译器根本不认识pNode

解决这个问题的方法有多种:

  1)第一种

  1. typedef struct tagNode
  2. {
  3.  char *pItem;
  4.  struct tagNode *pNext;
  5. } *pNode;

  2)第二种

  1. typedef struct tagNode *pNode;
  2. struct tagNode
  3. {
  4.  char *pItem;
  5.  pNode pNext;
  6. };

  注意:在这个例子中,你用typedef给一个还未完全声明的类型起新名字。C语言编译器支持这种做法。

  3)、规范做法:

  1. struct tagNode
  2. {
  3.  char *pItem;
  4.  struct tagNode *pNext;
  5. };
  6. typedef struct tagNode *pNode;

关于typedef的用法总结