C语言typedef用法总结
黄海涛,2012-3-11
C语言中的typedef可以让人感觉很清新,但也可以让人感觉神秘。当你一层层剥开它的时候,神秘的面纱终会摘下……
让我们一起来探究其中的秘密吧!
一、 概述
1、 类型定义符typedef
C语言提供了一个称为typedef的工具,它允许你为各种数据类型定义新的名字。
定义形式:
typedef 原类型名 新类型名;
它的格式与变量声明完全一样,只是把typedef这个关键字放在声明的前面,但typedef并不
创建变量,而是为指定类型引入一个新的名字。
2、 实质
其实质是:为现有类型取个新名字,它并没有引入新的类型。
typedef是一种声明形式,它为一种类型引入新的名字,而不是产生新的类型,也不会为变量分配空间。
3、 作用时机
在某些方面,typedef类似于宏文本替换,但typedef是类型定义符,在编译时会有相应类型的检查。typedef是由编译器解释的。
▲typedef与#define的区别
A.#define后面没有分号,而typedef后面有分号;
B.#define不是关键字,而typedef是关键字;
C.宏定义中宏名紧跟着#define,而typedef中的类型名并不紧接其后;
D.可以用其他类型说明符对宏名进行扩展,但对typedef定义的类型名却不行;例如:
#define INT_TYPE int unsigned INT_TYPE i; /*没有问题*/ typedef int INT_TYPE; unsigned INT_TYPE i; /*错误!非法*/ |
E.在连续几个变量声明中,typedef定义的类型名可以保证声明中所有的变量均为同一种类型,而#define定义的宏名则无法保证。
4、 使用原因
1)表达方式更简洁,简化编程;
2)使程序参数化,提高程序的可移植性;
3)为程序提供更好的说明性,可以引入一个易记且意义明确的新名字,提升可维护性。
5、 缺点
允许一些看上去混乱的语法,可以把几个声明放在一个声明中。如:
typedef int *ptr, (fun)(), arr[5]; //语法没有问题 /* ptr是“指向int的指针”类型 * fun是“指向返回值为int的函数的指针”类型 * arr是“长度为5的int型数组”类型 */ const unsigned long typedef int volatile *ptr; /* typedef可以嵌入到声明的中间部分*/ |
二、 使用typedef声明定义时的限制
1、 原类型可以带有类型限定符
typedef const int CINT /*原类型中含有const类型限定符*/ |
2、 原类型可以是typedef声明的新类型名
typedef unsigned char CK_BYTE; typedef CK_BYTE CK_CHAR; |
3、 原类型不可带有存储类别
typedef static int SINT; /*错误,指定的存储类不能多于1个*/ typedef register int RIN; |
存储类关键字:auto、extern、register、static与typedef
但在存储类说明符中,typedef是个例外,它不会真正影响对象的存储特性。其他存储类说明符确定所声明对象的生存期。
三、 typedef基本数据类型
typedef的一个重要用途就是声明定义机器无关的类型名,提高程序的可移植性。
像操作硬件设备等使用长度明确的数据,对应的类型长度也应该明确。在32位机器上可以如下声明定义:
typedef signed char S8; typedef unsigned char U8; typedef signed short S16; typedef unsigned short U16; typedef signed int S32; typedef unsigned int U32; |
带符号的可能用到的比较少。
你也可能如下声明定义:
typedef unsigned char BYTE; typedef unsigned short WORD; typedef unsigned int DWORD; typedef void VOID; |
相对应的指针:
typedef unsigned char *BYTE_PTR; typedef unsigned short *WORD_PTR; typedef unsigned int *DWORD_PTR; typedef void *VOID_PTR; |
如果要将程序移植到另一个平台,程序中使用的是typedef的新类型名,那么移植时修改typedef中相应信息即可。
四、 typedef构造类型
C语言中的构造类型主要包括:数组类型、结构体类型与共用体类型。
1、数组类型
typedef int ARRAY[10]; |
当你想定义多个同样大小的数组时,直接用新类型名定义即可。如:
ARRAY a, b; /*a与b都是拥有10个int型数据的数组*/ |
2、结构体类型
struct tagMyStruct { int num; long lLength; }; struct tagMyStruct a; /*声明定义结构体变量*/ typedef struct tagMyStruct MyStruct; /*为该结构体引入一个新类型名*/ MyStruct a; /*与struct tagMyStruct a;等效*/ tagMyStruct b; /*却不行,它只是一个标签而已*/ |
整体声明定义:
typedef struct tagMyStruct { int num; long lLength; }MyStruct; /* MyStruct是该结构引入的新类型名*/ struct tagMyStruct val; /*使用结构标签tagMyStruct*/ c语言struct用法例子MyStruct val; /*使用结构新类型名MyStruct*/ /*请区别以下写法:*/ struct tagMyStruct { int num; long lLength; }MyStruct; /* 此处的MyStruct是该结构声明的变量*/ MyStruct val; /*错误*/ |
结构体中的问题:
typedef struct tagNode { int data; pNode pNext; /*错误,pNode类型名还不存在*/ } *pNode; |
C语言允许在结构体中包含指向它自己的指针,在建立链表等数据结构时可以看到大量这样的例子。解决办法有多种:
1)
typedef struct tagNode { int data; struct tagNode *pNext; /*使用前面已知的标签*/ } *pNode; |
2)
typedef struct tagNode *pNode; /*支持给未声明的类型引入新名字*/ struct tagNode { int data; pNode pNext; }; |
3)规范的写法
struct tagNode { int data; struct tagNode *pNext; }; typedef struct tagNode *pNode; |
五、 typedef指针类型
1、 简单使用
typedef char *pStr; pStr1 s1, s2; /*s1与s2均被声明为char类型指针*/ |
使用const类型限定符带来的困惑:
typedef char * pStr; char string[4] = "abc"; /*const限定的是char,即指针p1所指的内容不能修改,但p1可以改变*/ const char *p1 = string; char const *p1 = string; /*const位于类型说明符前后等价*/ p1++; /*可以正确执行*/ /*const限定的是(char *),即指针p1所指的内容可以修改,但p1不能变化*/ char *const p1 = string; p1++; /*错误,不能执行这个操作*/ /*const限定的是pStr,也就是(char *),因为pStr是一个整体,即指针p2所指的内容可以修改,但p2不能变化。编译器认为pStr跟普通数据类型没有什么区别,它只是我们自己引入的一个新类型名而已*/ const pStr p2 = string; p2++; /*错误,不能执行这个操作*/ /*const限定的也是pStr,即指针p2所指的内容可以修改,但p2不能变化*/ pStr const p2 = string; p2++; /*错误,不能执行这个操作*/ |
解决办法:在typedef时指明const类型限定符
typedef const char *pcStr; pcStr p2 = string; p2++; /*可以正确执行*/ |
2、 函数指针
typedef int (*PFUN)(char *, char *); /*为函数指针引入了一个新类型名PFUN,是“一个指向函数的指针,该函数具有两个char *型参数,返回值类型为int”*/ PFUN strcmp, numcmp; /*都是指向函数的指针*/ |
3、 函数指针与数组
/*a为函数指针,该函数有一个int型参数,且返回值类型为int*/ int (*a)(int); /*a为有10个函数指针的数组,该函数有一个int型参数,且返回值类型为int*/ int (*a[10])(int); typedef int (*PFUN)(int); PFUN a[10]; /*在使用typedef引入新类型名PFUN后,我们看到了熟悉的普通数组声明方式*/ |
4、 复杂的声明
/*下面的这个声明让人望而生畏,很难弄清楚是做什么用的*/ int (*Register(int (*pf)(const char *, const char *)))(const char *, const char *); /*我们将它的构成解剖,然后使用typedef*/ /*它由两大部分构成*/ int (*pf)(const char *, const char *) ① int (*Register( ① ))(const char *, const char *); ② /*第一部分看到有些眼熟了吧?*/ typedef int (*PFUN)(const char *, const char *); PFUN Register(PFUN pf); |
有人可能会问,会有程序员写这样的代码吗?它有什么用呢?典型的例子是signal()原型的声明,signal()是一个系统调用,用于通知运行时系统,当某种特定的“软件中断”发生时
调用特定的程序。你可以通过参数传递告诉它中断的类型以及用于处理中断的程序。在ANSI C标准中,signal()的声明如下:
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论