您现在的位置是:首页 >技术杂谈 >C——Typedef是什么?如何使用?有何便利之处?网站首页技术杂谈

C——Typedef是什么?如何使用?有何便利之处?

zhonguncle 2023-06-17 16:00:02
简介C——Typedef是什么?如何使用?有何便利之处?

Typedef 是什么?

typedef是 C 语言中的一个特色功能,被用于创建新的类型名称,从名称“type def(ine)”也可以看出其功能。typedef类似于 Unix 中的alias程序的功能,为一个对象添加另外一个名称,typedef使得多个名称其实对应的是同一个程序,但是typedef操作的对象是数据类型,也就是给数据类型“起外号”,这个外号一般首字母大写,用于表示不是基础数据类型

在 C 语言中,typedef与宏#define很相似,二者的区别放到最后,因为需要先理解typedef,才能理解其与宏的区别。

Typedef 如何使用?

比如说,在 C 语言中,是有字符串的概念的:char类型的数组,最后一个元素为表示字符串结束。并且元素类型为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
", 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还有两个优点:

  1. 参数化程序,提高可移植性。这点现在的开发用处比较少,早期计算机类的数据类型在不同的计算机上的是不同的,有些是大小,有些是数据类型的名称。如果使用typedef的话,移植的时候只要修改typedef部分即可。标准库中的size_tptrdiff_t就是两个案例。
  2. 让代码更佳易懂,因为指针在复杂数据类型中,会比较难以理解,如果使用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 == '') {
            return 0;
        }
    }
    return *s - *t;
}

在声明的时候就可以写成:

PFI strcmp;

对比原本的

int strcmp(char *, char *);

是不是简洁了很多。如果同时有多个类似的函数,那么写在同一行也可以,更加简洁。

希望能帮到有需要的人~

风语者!平时喜欢研究各种技术,目前在从事后端开发工作,热爱生活、热爱工作。