原文链接

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

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

  1. typedef int BOOL;
  2. #define TRUE 1
  3. #define FALSE 0

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

  1. BOOL bflag=TRUE;

typedef的4种用法

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

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

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

  1. typedef unsigned int COUNT;

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

  1. typedef long double REAL;

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

  1. typedef double REAL;

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

  1. typedef float REAL;

这样,当跨平台移植程序时,我们只需要修改一下 typedef 的定义即可,而不用对其他源代码做任何修改。其实,标准库中广泛地使用了这个技巧,比如 size_t 在 VC++2010 的 crtdefs.h 文件中的定义如下所示:

  1. #ifndef _SIZE_T_DEFINED
  2. #ifdef _WIN64
  3. typedef unsigned __int64 size_t;
  4. #else
  5. typedef _W64 unsigned int size_t;
  6. #endif
  7. #define _SIZE_T_DEFINED
  8. #endif

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

以结构体为例,下面我们定义一个名为 Point 的结构体:

  1. struct Point
  2. {
  3. double x;
  4. double y;
  5. double z;
  6. };

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

  1. struct Point oPoint1={100,100,0};
  2. struct Point oPoint2;

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

  1. typedef struct tagPoint
  2. {
  3. double x;
  4. double y;
  5. double z;
  6. } Point;

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

  1. struct tagPoint
  2. {
  3. double x;
  4. double y;
  5. double z;
  6. } ;

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

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

  1. typedef struct tagPoint Point

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

  1. Point oPoint1={100,100,0};
  2. Point oPoint2;

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

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

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

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

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

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

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

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

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

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

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

它的定义方法很简单,与为基本数据类型定义新的别名方法一样,示例代码如下所示:

  1. typedef int INT_ARRAY_100[100];
  2. INT_ARRAY_100 arr;

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

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

  1. typedef char* PCHAR;
  2. PCHAR pa;

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

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

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

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

小心使用 typedef 带来的陷阱

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

  1. typedef char* PCHAR;
  2. int strcmp(const PCHAR,const PCHAR);

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

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

  1. typedef const char* PCHAR;
  2. int strcmp(PCHAR, PCHAR);

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

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

  1. typedef static int INT_STATIC;

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

更多阅读:

关于typedef的用法总结

typedef用法总结之续

C语言typedef详解的更多相关文章

  1. 深入理解C语言 - 指针详解

    一.什么是指针 C语言里,变量存放在内存中,而内存其实就是一组有序字节组成的数组,每个字节有唯一的内存地址.CPU 通过内存寻址对存储在内存中的某个指定数据对象的地址进行定位.这里,数据对象是指存储在 ...

  2. c++、Java、python对应的编译型语言和解释性语言区别详解

    1.首先明确一点: 高级语言是不能直接在CPU上运行的.CPU只能处理机器语言,就是黑客帝国里面那个10101010101110的数字流. 那么为了让机器语言能够在CPU上运行,那么就必须将其变成机器 ...

  3. (六)C语言之typedef详解

    1.typedef可以看作type define的缩写,顾名思义就是类型定义,也就是说它只是给已有的类型重新定义了一个方便使用的别名,并没有产生新的数据类型.typedef的使用与宏定义define有 ...

  4. C语言指针详解

    前言 这不是我第一次写关于C指针的文章了,只是因为指针对于C来说太重要,而且随着自己编程经历越多,对指针的理解越多,因此有了本文. 为什么需要指针? 指针解决了一些编程中基本的问题. 第一,指针的使用 ...

  5. C语言正则表达式详解 regcomp() regexec() regfree()详解

    标准的C和C++都不支持正则表达式,但有一些函数库可以辅助C/C++程序员完成这一功能,其中最著名的当数Philip Hazel的Perl-Compatible Regular Expression库 ...

  6. C语言关键字详解

    相对于其他语言来说,C语言的关键字算是少的了.在C98中关键子总共只有32个,我们来分析一下每个关键字在C语言中它独特的作用. 1.关于数据类型的关键字 (1) char :声明字符型变量或函数  ( ...

  7. C语言文件详解

    1.C语言FILE类,在stdio.h头文件中,FILE类是一个结构体:定义如下: 通过typedef定义了 文件类型 的别名: “FILE”,这样以后需要读写文件的时候直接定义FILE就行了.   ...

  8. c/c++中typedef详解

    1. typedef 最简单使用 typedef long byte_4; // 给已知数据类型long起个新名字,叫byte_4 你可以在任何需要 long 的上下文中使用 byte_4.注意 ty ...

  9. 小程序脚本语言WXS详解

    WXS脚本语言是 Weixin Script脚本的简称,是JS.JSON.WXML.WXSS之后又一大小程序内部文件类型.截至到目前小程序已经提供了5种文件类型. 解构小程序的几种方式,其中一种方式就 ...

随机推荐

  1. windows10下如何完全卸载串口驱动?

    答: 所需步骤如下: 1. 以管理员身份启动cmd 2. 在cmd中输入两行命令来启动设备管理器 3. 设置view->Show hidden devices 4. 在Ports (COM &a ...

  2. 理解JVM

    1.JVM运行时数据区 2.方法区 方法区垃圾回收的条件:该类的所有实例(堆内存中)被回收:加载该类字节码的类加载器被回收:所有的类对象(如Student.class)的引用被回收 一般采用可达性分析 ...

  3. Fragment的生命周期和activity如何的一个关系

  4. IDEA 常用插件及快捷键总结

    现在开发中和日常自己开发都统一换成了 IDEA 进行开发了.现在针对自己常用到的插件和快捷键进行总结记录下. 插件 Alibaba Java Coding Guidelines:阿里巴巴编码规约 Gr ...

  5. SqlServer:SqlServer(sql,游标,定时作业,行转列,列转行,公用表达式递归,merge合并)

    1.加载驱动: Class.forName("com.microsoft.sqlserver.jdbc.SQLServerDriver"); DriverManager.getCo ...

  6. python-爬虫-bs4-BeautifulSoup

    代码的使用流程: 核心思想:将html文档转换成Beautiful对象,然后调用该对象中的 属性和方法进行html文档指定内容的定位查找. 1 导包:from bs4 import Beautiful ...

  7. MathType 6.0中MT Extra(TrueType)问题

    问题 MathType 6.0中MT Extra(TrueType)字体问题在打开MathType6.0时,有时会提示MathType需要安装一个较新版本的MT Extra(TrueType)字体,这 ...

  8. IDEA添加Lombok插件

    背景: 最近老大给了一个项目,是个雏.一看实体类就懵逼了,没有getter.setter和构造方法,导致service和controller全报红线,私有属性也没有注释.按规矩,心里先把这位前辈骂10 ...

  9. 【机器学习】Learning to Rank 简介

    Learning to Rank 简介 去年实习时,因为项目需要,接触了一下Learning to Rank(以下简称L2R),感觉很有意思,也有很大的应用价值.L2R将机器学习的技术很好的应用到了排 ...

  10. 【Ansible】记一次技术博客害死人的经历——ansible模板变量注入探究

    风和日丽,夏天的北京湿热并举,睁不开的眼睛里,横竖都看着是“吃人”. 带薪学习的日子不好过,要在几天内迅速掌握导师下发要求学习的技能,看着以前一起蹲IT坑的同事人来人往,用隔壁同性黄同学的话来说,就是 ...