typedef:创建新类型嗯,与其说是创建新类型,不如说是给已有类型取新名字。表面上看这似乎没什么意义,但我们确实可以用它让代码更整洁。
typedef 理论基本上,你拿一个已有的类型,用 typedef 给它起个别名。
像这样:
typedef int antelope; // 让 "antelope" 成为 "int" 的别名
antelope x = 10; // 类型 "antelope" 与类型 "int" 相同你可以对任何已有类型这么做。甚至可以用逗号列表一次创建多个类型:
typedef int antelope, bagel, mushroom; // 这些都是 "int"这真的很有用,对吧?你能打 mushroom 而不是 int?你肯定对这个特性超级兴奋吧!
好吧,讽刺教授——我们马上就会看到它更常见的用法。
typedef 遵循常规的作用域规则。
正因如此,把 typedef 放在文件作用域(“全局”)中相当常见,这样所有函数都能随意使用这些新类型。
typedef 实践所以把 int 改名成别的,并没多令人兴奋。我们来看看 typedef 通常出现在哪些地方。
typedef 与 struct 有时会用一个新名字 typedef 一个 struct,这样你就不必一遍遍地敲 struct 这个词。
struct animal {
char *name;
int leg_count, speed;
};
// 原名 新名
// | |
// v v
// |-----------| |----|
typedef struct animal animal;
struct animal y; // 这样可以
animal z; // 这样也可以,因为 "animal" 是别名就我个人而言,我不太喜欢这种做法。我喜欢在类型前加上 struct 时,代码所具有的那份清晰感:程序员知道自己拿到的是什么。但这种做法真的很常见,所以我把它收在这里。
现在我想用你可能常见的方式,把完全相同的示例再走一遍。我们要把 struct animal 放进 typedef 里。你可以像这样把它们捏在一起:
// 原名
// |
// v
// |-----------|
typedef struct animal {
char *name;
int leg_count, speed;
} animal; // <-- 新名称
struct animal y; // 这样可以
animal z; // 这样也可以,因为 "animal" 是别名这和上一个示例完全相同,只是更简洁。
但还不止这些!你可能还会在代码里见到另一种常见简写,用的是所谓的匿名结构体82。事实证明,在许多地方你其实并不需要给结构体命名,而配合 typedef 就是其中之一。
我们用匿名结构体把同一个例子再做一遍:
// 匿名结构体!它没有名字!
// |
// v
// |----|
typedef struct {
char *name;
int leg_count, speed;
} animal; // <-- 新名称
//struct animal y; // 错误:这不再有效——没有这样的结构体!
animal z; // 这样可以,因为 "animal" 是别名再举个例子,我们可能会见到这样的东西:
typedef struct {
int x, y;
} point;
point p = {.x=20, .y=40};
printf("%d, %d\n", p.x, p.y); // 20, 40
typedef 与其他类型把 typedef 用在 int 这样的简单类型上并不是完全没用……它帮你把类型抽象出来,以便日后更容易修改。
例如,如果你的代码里有一亿个地方都写着 float,而后来因为某些原因你发现必须把它们全改成 double,那可就痛苦了。
但如果你事先稍微准备一下,写成:
typedef float app_float;
// 以及
app_float f1, f2, f3;那么之后如果你想换成别的类型,比如 long double,只需改一下 typedef:
// 大功告成!
// |---------|
typedef long double app_float;
// 而且无需修改这一行:
app_float f1, f2, f3; // 现在这些都是 long doubletypedef 与指针你可以创建一个本身是指针的类型。
typedef int *intptr;
int a = 10;
intptr x = &a; // "intptr" 是 "int*" 类型我真的很不喜欢这种做法。它掩盖了 x 是指针类型这一事实,因为你在声明里看不到 *。
依我看,最好明确表示出你声明的是指针类型,这样其他开发者一眼就能看出来,不会误以为 x 是非指针类型。
但据最近一次统计,大概有 832,007 个人持不同意见。
typedef 与大小写我见过 typedef 上五花八门的大小写写法。
typedef struct {
int x, y;
} my_point; // 小写蛇形命名
typedef struct {
int x, y;
} MyPoint; // 驼峰命名
typedef struct {
int x, y;
} Mypoint; // 首字母大写
typedef struct {
int x, y;
} MY_POINT; // 全大写蛇形命名C11 规范没有强行规定哪一种,示例里既有全大写也有全小写。
K&R2 以首字母大写为主,但也给出了一些全大写和蛇形命名(带 _t)的示例。
如果你手头有在用的风格指南,就照它来。如果没有,去找一份,然后照它来。
typedef 语法有点古怪,而且据我的经验很少见到,但你可以 typedef 一个包含若干元素的数组。
// 让 five_ints 类型成为含 5 个 int 的数组
typedef int five_ints[5];
five_ints x = {11, 22, 33, 44, 55};我不喜欢它,因为它掩盖了变量的数组属性,但这样做是可行的。