admin 管理员组

文章数量: 887053


2024年1月23日发(作者:mybatisplus wrapper)

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

typedef unsigned char

typedef signed short

typedef unsigned short

typedef signed int

typedef unsigned int

S8;

U8;

S16;

U16;

S32;

U32;

带符号的可能用到的比较少。

你也可能如下声明定义:

typedef unsigned char

typedef unsigned short

typedef unsigned int

typedef void

BYTE;

WORD;

DWORD;

VOID;

*BYTE_PTR;

*WORD_PTR;

*DWORD_PTR;

*VOID_PTR;

相对应的指针:

typedef unsigned char

typedef unsigned short

typedef unsigned int

typedef void

如果要将程序移植到另一个平台,程序中使用的是typedef的新类型名,那么移植时修改typedef中相应信息即可。

四、typedef构造类型

C语言中的构造类型主要包括:数组类型、结构体类型与共用体类型。

1、数组类型

typedef int ARRAY[10];

当你想定义多个同样大小的数组时,直接用新类型名定义即可。如:

ARRAY a, b;

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*/

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

{

/*a与b都是拥有10个int型数据的数组*/

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()的声明如下:

void (*signal(int sig, void (*func)(int)))(int);

/*我们使用上面同样的方式解剖它,然后使用typedef*/

/*它由两大部分构成*/

void (*func)(int) ①

void (*signal(int sig, ①))(int); ②

/*跟上面的例子同样的简洁吧?*/

typedef void (*ptr_to_func)(int);

ptr_to_func signal(int sig, ptr_to_func);

由于水平有限,文中肯定存在很多不足之处,恳请阅读者批评指正,相互交流,学习提高。

六、参考资料

1、《C程序设计》(第三版):谭浩强著,清华大学出版社2005.07

2、《C程序设计语言(The C Programming Language)》(第2版中英文版):(美)Brian

han,Dennis e著,徐宝文 李志译,机械工业出版社2004 年1月

3、《C专家编程(Expert C Programming)》(中英文版):(美)林登(LinDen,P.V.D)著,徐波译,人民邮电出版社2002.12

4、《C陷阱与缺陷(C Traps And Pitfalls)》(中英文版):(美)Andrew Koenig著,高巍译,人民邮电出版社2003

5、《C语言深度解剖》陈正冲著,北京航空航天大学出版社2010

6、《C语言参考手册(C:A Reference Manual)》(第五版):(美)Samuel on III,Guy

Jr.著,邱仲潘等译,机械工业出版社2003 年8月

7、《想成为嵌入式程序员应知道的0x10个基本问题.doc》作者:Jones Nigel


本文标签: 类型 声明 使用