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小时内删除。