C语言typedef详解
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
 
2) 为自定义数据类型(结构体、共用体和枚举类型)定义简洁的类型名称
以结构体为例,下面我们定义一个名为 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;
 
3) 为数组定义简洁的类型名称
它的定义方法很简单,与为基本数据类型定义新的别名方法一样,示例代码如下所示:
- typedef int INT_ARRAY_100[100];
 - INT_ARRAY_100 arr;
 
4) 为指针定义简洁的名称
对于指针,我们同样可以使用下面的方式来定义一个新的别名:
- 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 给予了整个指针本身常量性,也就是形成了常量指针“char*const(一个指向char的常量指针)”。即它实际上相当于“char*const”,而不是“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 中的报错信息为“无法指定多个存储类”。
更多阅读:
C语言typedef详解的更多相关文章
- 深入理解C语言 - 指针详解
		
一.什么是指针 C语言里,变量存放在内存中,而内存其实就是一组有序字节组成的数组,每个字节有唯一的内存地址.CPU 通过内存寻址对存储在内存中的某个指定数据对象的地址进行定位.这里,数据对象是指存储在 ...
 - c++、Java、python对应的编译型语言和解释性语言区别详解
		
1.首先明确一点: 高级语言是不能直接在CPU上运行的.CPU只能处理机器语言,就是黑客帝国里面那个10101010101110的数字流. 那么为了让机器语言能够在CPU上运行,那么就必须将其变成机器 ...
 - (六)C语言之typedef详解
		
1.typedef可以看作type define的缩写,顾名思义就是类型定义,也就是说它只是给已有的类型重新定义了一个方便使用的别名,并没有产生新的数据类型.typedef的使用与宏定义define有 ...
 - C语言指针详解
		
前言 这不是我第一次写关于C指针的文章了,只是因为指针对于C来说太重要,而且随着自己编程经历越多,对指针的理解越多,因此有了本文. 为什么需要指针? 指针解决了一些编程中基本的问题. 第一,指针的使用 ...
 - C语言正则表达式详解 regcomp() regexec() regfree()详解
		
标准的C和C++都不支持正则表达式,但有一些函数库可以辅助C/C++程序员完成这一功能,其中最著名的当数Philip Hazel的Perl-Compatible Regular Expression库 ...
 - C语言关键字详解
		
相对于其他语言来说,C语言的关键字算是少的了.在C98中关键子总共只有32个,我们来分析一下每个关键字在C语言中它独特的作用. 1.关于数据类型的关键字 (1) char :声明字符型变量或函数 ( ...
 - C语言文件详解
		
1.C语言FILE类,在stdio.h头文件中,FILE类是一个结构体:定义如下: 通过typedef定义了 文件类型 的别名: “FILE”,这样以后需要读写文件的时候直接定义FILE就行了. ...
 - c/c++中typedef详解
		
1. typedef 最简单使用 typedef long byte_4; // 给已知数据类型long起个新名字,叫byte_4 你可以在任何需要 long 的上下文中使用 byte_4.注意 ty ...
 - 小程序脚本语言WXS详解
		
WXS脚本语言是 Weixin Script脚本的简称,是JS.JSON.WXML.WXSS之后又一大小程序内部文件类型.截至到目前小程序已经提供了5种文件类型. 解构小程序的几种方式,其中一种方式就 ...
 
随机推荐
- tomcat8踩坑:url包含|等特殊字符报错400的问题
			
这个问题纠缠了我很久了,终于在今天早上解决了,感谢自己的不放弃和不断尝试的决心,我坚信,我可以找到解决方式!! 项目用的spring boot+spring security框架,关于统一错误页面在开 ...
 - mysql之备份与恢复
			
数据备份全备 备份命令 :mysqldump把数据库的数据以sql语句导出属于逻辑备份 格式 : mysqldump -uroot -p123456 -S 多实例的mysql.sock 数据库名 &g ...
 - Bootstrap-CSS:目录
			
ylbtech-Bootstrap-CSS:目录 1.返回顶部 1. 2. 2.返回顶部 3.返回顶部 4.返回顶部 5.返回顶部 1. 2. 6.返回顶部 7.返回顶部 ...
 - java初级之数组详解
			
一,数组的概念: 数组是为了存储同一种数据多个元素的集合,也可以看成是一个容器,数组既可以存储基本数据类型,也可以存储引用数据类型,数组是为了存储同种数据类型的多个值. 1.1.1,一维数组重点: 数 ...
 - .net core中读取配置文件
			
1)先看丑陋的方法 读取 appsettings.json 然后在 Startup 的 ConfigureServices() 方法中进行注入: public IConfigurationRoot ...
 - 了解XPath与XPath轴
			
XPath 是一门在 XML 文档中查找信息的语言.XPath 用于在 XML 文档中通过元素和属性进行导航. 节点(Node) 在 XPath 中,有七种类型的节点:元素.属性.文本.命名空间.处理 ...
 - Android开发 发布相关知识
			
1 三种BuildSystem简介 注意:ADT不要用了,在2017版本已经没有了.而且这就是一个巨坑,以前打包cocos的时候,学习的时候用这个,ADT是eclipse中的一个集成的东东,已经绝版, ...
 - 机器学习笔记:支持向量机(svm)
			
支持向量机(svm)英文为Support Vector Machines 第一次接触支持向量机是2017年在一个在线解密游戏"哈密顿行动"中的一个关卡的二分类问题,用到了台湾教授写 ...
 - mac 上iterm终端连接Linux服务后 中文为乱码问题
			
https://www.jianshu.com/p/8b00f71b2177 编辑 ssh 配置vim /etc/ssh/ssh_config修改如下:Host *#SendEnv LANG LC_* ...
 - 好的python链接
			
海艳师姐博客园: https://www.cnblogs.com/haiyan123/p/8387770.html