C——Typedef是什么?如何使用?有何便利之处?
Typedef 是什么?
typedef
是 C 语言中的一个特色功能,被用于创建新的类型名称,从名称“type def(ine)”也可以看出其功能。typedef
类似于 Unix 中的alias
程序的功能,为一个对象添加另外一个名称,typedef
使得多个名称其实对应的是同一个程序,但是typedef
操作的对象是数据类型,也就是给数据类型“起外号”,这个外号一般首字母大写,用于表示不是基础数据类型。
在 C 语言中,typedef
与宏#define
很相似,二者的区别放到最后,因为需要先理解typedef
,才能理解其与宏的区别。
Typedef 如何使用?
比如说,在 C 语言中,是有字符串的概念的:char
类型的数组,最后一个元素为\0
表示字符串结束。并且元素类型为char
的数组其实等价于指向char
的指针。但是 C 语言中并没有String
这种数据类型。那么就可以使用以下语句来实现同等的功能:
//String是一个指针,*String(就是该指针的内容)等于char。换句话说,String 等于 char *
typedef char *String
从这里也可以看出来,这个外号并不是在typedef
后面,而是在数据类型后面的变量的位置。(C 语言中,声明、定义变量的时候,变量是不是在类型后面?)
这时候便可以使用以下语句声明、赋值、输出“字符串”类型的数据。如下 :
#include <stdio.h>
int main()
{
typedef char *String;
String p = "abc";
printf("%s\n", p);
return 0;
}
输出为:
abc
再次强调,typedef
并没有创建新的数据类型,只是起了个“外号”,这里的字符串也是利用 C 语言本身的机制实现的。
当然这种方法不是很常见,大多数情况不会给基础数据类型“起外号”,毕竟大部分基础数据类型的名称已经很简洁、易懂了,字符串是个例外。最常见的是在使用结构体自定义数据类型的时候,使用typedef
来找一个简单些或者更易懂的同义词,而且还能让代码更简洁、高效。
比如下面这段代码,是很经典的二叉树节点的结构体:
struct tnode {
char *word;
int count;
struct tnode *left;
struct tnode *right;
};
新建一个新的节点,并为其分配空间的方法如下:
struct tnode *talloc(void)
{
return (struct tnode *) malloc(sizeof(struct tnode));
}
如果使用typedef
的方法,也就是在声明结构体tnode
的同时,用typedef
给它起一个“外号”Treenode
,如下:
typedef struct tnode {
char *word;
int count;
Treeptr left;
Treeptr right;
} Treenode;
然后再使用typedef
定义一个“外号”*Treeptr
:
typedef struct tnode *Treeptr;
这样的话,新建并分配内存的方法不仅简洁了,而且可以写成没有指针符号*
的样式,如下:
Treenode talloc(void)
{
return (Treeptr) malloc(sizeof(struct Treenode));
}
对比一下之前的版本,是不是容易理解了许多。
Typedef 有何便利之处?
typedef
与#define
的主要目的都是为了让代码更加简洁,也就是让代码更加美观。
除此之外,typedef
还有两个优点:
- 参数化程序,提高可移植性。这点现在的开发用处比较少,早期计算机类的数据类型在不同的计算机上的是不同的,有些是大小,有些是数据类型的名称。如果使用
typedef
的话,移植的时候只要修改typedef
部分即可。标准库中的size_t
和ptrdiff_t
就是两个案例。 - 让代码更佳易懂,因为指针在复杂数据类型中,会比较难以理解,如果使用
typedef
就简单多了。上一节中的talloc
便是一个例子。
Typedef 与 #define 的不同之处
接下来就可以解释一下typedef
与#define
的不同之处了。
typedef
与#define
的主要目的都是为了让代码更加简洁,所以都有文本替换的功能。二者不同之处在于,typedef
由于可以被编译器理解,所以文本替换也比宏要强大的多。
宏只能做简单的文本替换,比如直接文本替换,简单的计算和操作。下面就是一个简单的文本替换案例:
#define MAXWORD 100
int a[MAXWORD];
在编译的时候,会先直接将int a[MAXWORD];
换成int a[100];
,也就是文本替换,再进行编译,并不会将MAXWORD
当作变量或常量去编译。所以宏所属的范围也称为预处理器(Preprocessor)。
而使用typedef
的话,就可以实现一些复杂的功能。比如说下面这行代码是新建一个类型PFI
,是指向有两个参数、参数类型为char *
、返回值为int
的函数的指针:
typedef int (*PFI)(char *, char *);
这样在声明一些函数的时候就非常方便,比如下面这个函数:
int strcmp(char *s, char *t)
{
for ( ; *s == *t; s++, t++) {
if (*s == '\0') {
return 0;
}
}
return *s - *t;
}
在声明的时候就可以写成:
PFI strcmp;
对比原本的
int strcmp(char *, char *);
是不是简洁了很多。如果同时有多个类似的函数,那么写在同一行也可以,更加简洁。
希望能帮到有需要的人~