【知识总结】typedef用法总结

一、概述

          是一种在计算机编程语言中用来声明自定义数据类型,配合各种原有数据类型来达到简化编程目的的类型定义关键字。typedef 声明,简称 typedef,为现有类型创建一个新的名字。比如人们常常使用 typedef 来编写更美观和可读的代码。所谓美观,意指 typedef 能隐藏笨拙的语法构造以及平台相关的数据类型,从而增强可移植性和以及未来的可维护性。

二、用法

          1、创建平台无关类型

           typedef 声明有助于创建平台无关类型,甚至能隐藏复杂和难以理解的语法。typedef 使用最多的地方是创建易于记忆的类型名,用它来归档程序员的意图。类型出现在所声明的变量名字中,位于 ''typedef'' 关键字右边。在编程中使用typedef的好处,除了为变量取一个简单易记且意义明确的新名称之外,还可以简化一些比较复杂的类型声明。比如:

           typedef      int I     NT32; /*将INT32定义为与int具有相同意义的名字,这样类型INT32就可用于类型声明和类型转换了,它和类型int完全相同。*/

           比如:     INT32          a;   // 定义整型变量a

                          (INT32)       b;   // 将其它的类型b转换为整型

         既然已经有了int这个名称,为什么还要再取一个名称呢?主要是为了提高程序的可移植性。比如,某种微处理器的int为16位,long为32位。如果要将该程序移植到另一种体系结构的微处理器,假设编译器的int为32位,long为64位,而只有short才是16位的,因此必须将程序中的int全部替换为short,long全部替换为int,如此这样修改势必工作量巨大且容易出错。如果将它取一个新的名称,然后在程序中全部用新取的名称,那么要移植的工作仅仅只是修改定义这些新名称即可。也就是说,只需要将以前的:

              typedef         int         INT16;                             替换成:                  typedef       short     INT16;

              typedef         long      INT32;                                                                 typedef       int          INT32;

         【疑问】为什么不用#define创建新的类型名呢?

比如:#define ptr_to_char char*

           ptr_to_char pch1, pch2;

          由于有了“#define ptr_to_charchar*”,因此“ptr_to_char pch1, pch2”可以展开为char *pch1, pch2;所以pch2为char型变量。

          如果用typedef来定义的话,其代码如下:

          typedef char*  ptr_to_char;

          ptr_to_char  pch1, pch2;

          则“ptr_to_char pch1, pch2”等价于

          char  *pch1;

          char  *pch2;

          因此,pch1、pch2都是指针。

          虽然#define语句看起来象typedef,但实际上却有本质上的差别。对于#define来说,仅在编译前对源代码进行了字符串替换处理;而对于typedef来说,它建立了一个新的数据类型别名。由此可见,只是将pch1定义为指针变量,却并没有实现程序员的意图,而是将pch2定义成了char型变量。

         2.代码简化

      typedef 在编译时被解释,因此让编译器来应付超越预处理器能力的文本替换。

        (1)用来掩饰复合类型:如指针与数组

       不用象下面这样重复定义有 81 个字符元素的数组:

  char   line[81];

  char   text[81];

  定义一个 typedef,每当要用到相同类型和大小的数组时,可以这样:

  typedef     char    Line[81];

  Line     text, secondline;

  getline(text);

  同样,可以象下面这样隐藏指针语法:

  typedef       char *      pstr;

  int      mystrcmp(pstr, pstr);

  这里将带我们到达第一个 typedef 陷阱。标准函数 strcmp()有两个const  char *类型的参数。因此,它可能会误导人们象下面这样声明 mystrcmp():

  int  mystrcmp(const pstr, const pstr);

  用GNU的gcc和g++编译器,是会出现警告的,按照顺序,const  pstr被解释为char*   const(一个指向 char 的常量指针),而不是char *(指向char 的指针)。这个问题很容易解决:

  typedef     const char*     cpstr;

  int     mystrcmp(cpstr, cpstr);// 现在是正确的

  记住:不管什么时候,只要为指针声明 typedef,那么都要在最终的 typedef 名称中加一个 const,以使得该指针本身所指对象不会通过指针被修改。

        (2)简化指针函数的声明

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

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

  PF     Register(PF pf);

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

  int (*Register (int (*pf)(const char *, const char *))) (const char *, const char *);

  很少有程序员理解它是什么意思,更不用说这种费解的代码所带来的出错风险了。显然,这里使用 typedef 不是一种特权,而是一种必需。持怀疑态度的人可能会问:"OK,有人还会写这样的代码吗?",快速浏览一下揭示signal()函数的头文件 ,一个有同样接口的函数。

  typedef 和存储类关键字(storage class specifier)

  这种说法是不是有点令人惊讶,typedef 就像 auto,extern,mutable,static,和 register 一样,是一个存储类关键字。这并不是说 typedef 会真正影响对象的存储特性;它只是说在语句构成上,typedef 声明看起来象 static,extern 等类型的变量声明。

        【错误】typedef   register int    FAST_COUNTER; // 编译通不过。问题出在你不能在声明中有多个存储类关键字。因为符号 typedef 已经占据了存储类关键字的位置,在 typedef 声明中不能用 register(或任何其它存储类关键字)。 

         3.typedef在结构体和链表中的使用

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

  typedef struct tagNode

  {

           char *pItem;

           pNode pNext;

  } *pNode;

         (1)在结构体中的使用

  如下代码所示:

  typedef struct tagMyStruct

  {

            int     iNum;

           long   iLength;

  } MyStruct;

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

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

  struct tagMyStruct

  {

          int      iNum;

         long    iLength;

  };

  分析:tagMyStruct称为“tag”,即“标签”,实际上是一个临时名字,struct 关键字和tagMyStruct一起,构成了这个结构类型,不论是否有typedef,这个结构都存在。我们可以用struct tagMyStruct varName来定义变量,但要注意,使用tagMyStruct varName来定义变量是不对的,因为struct 和tagMyStruct合在一起才能表示一个结构类型。

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

  typedef struct     tagMyStruct     MyStruct;

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

  (2)在链表中的使用

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

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

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

方法一:方法二:方法三(规范做法):

typedef struct tagNode

{

    char *pItem;

    struct tagNode *pNext;

}*pNode;

typedef struct tagNode *pNode;

struct tagNode

{

  char *pItem;

  pNode pNext;

};

struct tagNode

{

  char *pItem;

  struct tagNode *pNext;

};

typedef struct tagNode *pNode;

转载于:https://www.cnblogs.com/lu-yang/archive/2011/11/25/2262898.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值