注意,转载至c语言中文网,因为转了人家的东西,广告我就不删了。


C语言中文网推出辅导班啦,包括「C语言辅导班、C++辅导班、算法/数据结构辅导班」,全部都是一对一教学:一对一辅导 + 一对一答疑 + 布置作业 + 项目实践 + 永久学习。QQ在线,随时响应!


C语言允许用户使用 typedef 关键字来定义自己习惯的数据类型名称,来替代系统默认的基本类型名称、数组类型名称、指针类型名称与用户自定义的结构型名称、共用型名称、枚举型名称等。一旦用户在程序中定义了自己的数据类型名称,就可以在该程序中用自己的数据类型名称来定义变量的类型、数组的类型、指针变量的类型与函数的类型等。

例如,C 语言在 C99 之前并未提供布尔类型,但我们可以使用 typedef 关键字来定义一个简单的布尔类型,如下面的代码所示:

typedef int BOOL;
#define TRUE 1
#define FALSE 0

定义好之后,就可以像使用基本类型数据一样使用它了,如下面的代码所示:

BOOL bflag=TRUE;

typedef的4种用法
在实际使用中,typedef 的应用主要有如下4种。

  1. 为基本数据类型定义新的类型名
    也就是说,系统默认的所有基本类型都可以利用 typedef 关键字来重新定义类型名,示例代码如下所示:

    typedef unsigned int COUNT;

而且,我们还可以使用这种方法来定义与平台无关的类型。比如,要定义一个叫 REAL 的浮点类型,在目标平台一上,让它表示最高精度的类型,即:

typedef long double REAL;

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

typedef double REAL;

甚至还可以在连 double 都不支持的平台三上,改为:

typedef float REAL;

这样,当跨平台移植程序时,我们只需要修改一下 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
#define _SIZE_T_DEFINED
#endif
  1. 为自定义数据类型(结构体、共用体和枚举类型)定义简洁的类型名称
    以结构体为例,下面我们定义一个名为 Point 的结构体:

    struct Point
    {
    double x;
    double y;
    double z;
    };

在调用这个结构体时,我们必须像下面的代码这样来调用这个结构体:

struct Point oPoint1={100,100,0};
struct Point oPoint2;

在这里,结构体 struct Point 为新的数据类型,在定义变量的时候均要向上面的调用方法一样有保留字 struct,而不能像 int 和 double 那样直接使用 Point 来定义变量。现在,我们利用 typedef 定义这个结构体,如下面的代码所示:

typedef struct tagPoint
{double x;double y;double z;
} Point;

在上面的代码中,实际上完成了两个操作:
1、定义了一个新的结构类型,代码如下所示:

struct tagPoint
{double x;double y;double z;
} ;

其中,struct 关键字和 tagPoint 一起构成了这个结构类型,无论是否存在 typedef 关键字,这个结构都存在。

2、使用 typedef 为这个新的结构起了一个别名,叫 Point,即:

typedef struct tagPoint Point

因此,现在你就可以像 int 和 double 那样直接使用 Point 定义变量,如下面的代码所示:

Point oPoint1={100,100,0};
Point oPoint2;

为了加深对 typedef 的理解,我们再来看一个结构体例子,如下面的代码所示:

typedef struct tagNode
{char *pItem;pNode pNext;
} *pNode;

从表面上看,上面的示例代码与前面的定义方法相同,所以应该没有什么问题。但是编译器却报了一个错误,为什么呢?莫非 C 语言不允许在结构中包含指向它自己的指针?

其实问题并非在于 struct 定义的本身,大家应该都知道,C 语言是允许在结构中包含指向它自己的指针的,我们可以在建立链表等数据结构的实现上看到很多这类例子。那问题在哪里呢?其实,根本问题还是在于 typedef 的应用。

在上面的代码中,新结构建立的过程中遇到了 pNext 声明,其类型是 pNode。这里要特别注意的是,pNode 表示的是该结构体的新别名。于是问题出现了,在结构体类型本身还没有建立完成的时候,编译器根本就不认识 pNode,因为这个结构体类型的新别名还不存在,所以自然就会报错。因此,我们要做一些适当的调整,比如将结构体中的 pNext 声明修改成如下方式:

typedef struct tagNode
{char *pItem;struct tagNode *pNext;
} *pNode;

或者将 struct 与 typedef 分开定义,如下面的代码所示:

typedef struct tagNode *pNode;
struct tagNode
{char *pItem;pNode pNext;
};

在上面的代码中,我们同样使用 typedef 给一个还未完全声明的类型 tagNode 起了一个新别名。不过,虽然 C 语言编译器完全支持这种做法,但不推荐这样做。建议还是使用如下规范定义方法:

struct tagNode
{char *pItem;struct tagNode *pNext;
};
typedef struct tagNode *pNode;
  1. 为数组定义简洁的类型名称
    它的定义方法很简单,与为基本数据类型定义新的别名方法一样,示例代码如下所示:

    typedef int INT_ARRAY_100[100];
    INT_ARRAY_100 arr;

  2. 为指针定义简洁的名称
    对于指针,我们同样可以使用下面的方式来定义一个新的别名:

    typedef char* PCHAR;
    PCHAR pa;

对于上面这种简单的变量声明,使用 typedef 来定义一个新的别名或许会感觉意义不大,但在比较复杂的变量声明中,typedef 的优势马上就体现出来了,如下面的示例代码所示:

int *(*a[5])(int,char*);

对于上面变量的声明,如果我们使用 typdef 来给它定义一个别名,这会非常有意义,如下面的代码所示:

// PFun是我们创建的一个类型别名
typedef int *(*PFun)(int,char*);
// 使用定义的新类型来声明对象,等价于int*(*a[5])(int,char*);
PFun a[5];

小心使用 typedef 带来的陷阱
接下来看一个简单的 typedef 使用示例,如下面的代码所示:

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

在上面的代码中,“const PCHAR” 是否相当于 “const char*” 呢?

答案是否定的,原因很简单,typedef 是用来定义一种类型的新别名的,它不同于宏,不是简单的字符串替换。因此,“const PCHAR”中的 const 给予了整个指针本身常量性,也就是形成了常量指针“charconst(一个指向char的常量指针)”。即它实际上相当于“charconst”,而不是“const char*(指向常量 char 的指针)”。当然,要想让 const PCHAR 相当于 const char* 也很容易,如下面的代码所示:

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

其实,无论什么时候,只要为指针声明 typedef,那么就应该在最终的 typedef 名称中加一个 const,以使得该指针本身是常量。

还需要特别注意的是,虽然 typedef 并不真正影响对象的存储特性,但在语法上它还是一个存储类的关键字,就像 auto、extern、static 和 register 等关键字一样。因此,像下面这种声明方式是不可行的:

typedef static int INT_STATIC;

不可行的原因是不能声明多个存储类关键字,由于 typedef 已经占据了存储类关键字的位置,因此,在 typedef 声明中就不能够再使用 static 或任何其他存储类关键字了。当然,编译器也会报错,如在 VC++2010 中的报错信息为“无法指定多个存储类”。

typedef的用法,C语言typedef详解相关推荐

  1. c语言指针用法及实际应用详解,通俗易懂超详细

    c语言指针用法及实际应用详解,通俗易懂超详细! \\\插播一条:文章末尾有惊喜哟~/// 今天给大家来讲解一下指针. 我会由浅到深,最后联合实际应用讲解,让大家学会指针的同时,知道大佬们都用指针来干嘛 ...

  2. 链表的基本操作(C语言)详解(摘取自C语言学习网2.5)

    链表的基本操作(C语言)详解 #include <stdio.h> #include <stdlib.h>typedef struct Link{int elem;struct ...

  3. c语言中常用命名空间,C语言命名空间详解.doc

    C语言命名空间详解 C语言命名空间详解 C语言命名空间分析准则: 在同一命名空间.相同作用域中,任何名字须具有唯一性 每个结构和联合内部都有自己的命名空间(独立于其他空间) 结构标签.联合标签.枚举标 ...

  4. C语言之详解#ifdef等宏

    C语言之详解#ifdef等宏 这几个宏是为了进行条件编译.一般情况下,源程序中所有的行都参加编译.但是有时希望对其中一部分内容只在满足一定条件才进行编译,也就是对一部分内容指定编译的条件,这就是&qu ...

  5. C#语言入门详解笔记(9)—P19 委托详解

    C#语言入门详解_哔哩哔哩_bilibiliC#语言入门详解搬运,随youtube上进度更新.刘老师的C#视频教程到30集就告一段落了,感谢刘老师在这5年间的付出.能上youtube的同学可以去刘老师 ...

  6. Java Web中的EL(表达式语言)详解

     Java Web中的EL(表达式语言)详解 表达式语言(Expression Language)简称EL,它是JSP2.0中引入的一个新内容.通过EL可以简化在JSP开发中对对象的引用,从而规范页面 ...

  7. Python的C语言接口 - 详解官方文档

    Python的C语言接口 - 详解官方文档 索引 Python的C语言接口 - 详解官方文档 介绍 / Introduce 代码标准 / Coding Standards 包含文件 / Include ...

  8. R语言——数据类型详解

    R语言--数据类型详解 R语言支持的数据类型 数值型 整数型 逻辑型 字符型 复数型 原生型 R语言的数据对象类型包括 向量:一个向量只能有一种数据类型 矩阵:一个矩阵只能有一种数据类型 数组:一个数 ...

  9. Go语言defer详解笔记

    Go语言defer详解 1.defer概述: ​ defer是用来声明一个延迟函数,并且将这个函数放到一个栈中,它的调用时间在return执行之前,详细来讲,它的执行时间在return的值赋值之后,在 ...

  10. python traceback_Python语言Traceback详解

    本文主要向大家介绍了Python语言Traceback详解,通过具体的内容向大家展示,希望对大家学习Python语言有所帮助. 刚接触Python的时候,简单的异常处理已经可以帮助我们解决大多数问题, ...

最新文章

  1. 糗事百科的网络爬虫(v0.2)源码及解析 .
  2. SAP-CO.创建成本中心,作业类型,内部订单
  3. Linq to Oracle 使用教程(八)使用 T4 模版生成代码
  4. [导入]【翻译】WF从入门到精通(第八章):调用外部方法及工作流
  5. 深入框架本源系列 —— Virtual Dom
  6. InfluxDB学习之InfluxDB数据保留策略(Retention Policies)
  7. php 内容采集_php开发工程师和大数据开发工程师有什么区别
  8. Java Colections 集合类 —— List、ArrayList、Set(HashSet)
  9. 山东大学软件学院计算机组成原理课程设计实验三
  10. 25 个你可能不知道的 Linux 真相
  11. bigemap离线手机离线地图的查看
  12. “快播时代”终结:清内容、关服务器!
  13. 【golang】处理jpeg图片压缩后方向发生变化问题
  14. CSMACA 与 CSMA/CD 区别
  15. SQL本地数据库连接服务器
  16. 详解SMS2003部署Windows 2003
  17. 续谈大数据之足球盘口赔率水位分析思路及其实现利器
  18. 臭氧味道虽“臭”,架不住它功能强大
  19. 古风男孩取名:有帝王气质的古风男孩名字
  20. virtual和override作用和使用场景及理解

热门文章

  1. LoRA FCC认证指引
  2. 《自然语言处理(哈工大 关毅 64集视频)》学习笔记:第五章 n-gram语言模型
  3. Linux学习笔记45——软件安装:源代码与 Tarball
  4. JavaScript Extensible Attributes 常用匹配方法
  5. 思科路由模拟器 -- (1)路由配置
  6. 解决方案|AttributeError: (module ‘scipy.sparse‘ has no attribute ‘coo_array‘)
  7. web报表中电子印章/水印的轻松实现
  8. 1.拖延症早睡早起篇
  9. Android 集成二维码扫描器
  10. 5G非授权频谱技术与应用建议