typedef 是 C 语言中的一个关键字,它的作用是为已有的数据类型创建一个新的名称(别名),它本身并不创建新的数据类型,而是为现有的类型定义了一个更容易理解、更简洁或更具描述性的别名。

可以把 typedef 理解为“类型定义器”或“类型重命名器”。
typedef 的基本语法
typedef 的语法结构非常清晰:
typedef existing_type new_type_name;
existing_type:已经存在的数据类型(可以是基本类型、指针、数组、结构体、联合体等)。new_type_name:你为这个类型定义的新名字。
一个简单的例子:
假设我们经常需要使用一个 unsigned long long 类型来表示内存地址或大数值,每次都写 unsigned long long 会很繁琐。

#include <stdio.h>
// 使用 typedef 为 unsigned long long 创建一个别名
typedef unsigned long long ull;
int main() {
// 我们可以直接使用 ull 来定义变量
ull a = 18446744073709551615ULL; // 比 unsigned long long 简洁多了
ull b = 0xFFFFFFFFFFFFFFFF;
printf("a = %llu\n", a);
printf("b = %llu\n", b);
return 0;
}
在这个例子中,ull unsigned long long 的别名,在编译时,编译器会把所有出现的 ull 都替换成 unsigned long long。
typedef 的主要用途和优点
使用 typedef 主要有以下好处:
- 提高代码可读性:为复杂的类型起一个有意义的名字,使代码意图更明确。
- 简化代码:用简短的别名代替冗长的类型声明。
- 提高代码可移植性:当需要修改数据类型时,只需修改
typedef定义,而不需要在整个代码库中替换所有该类型的使用。 - 增强代码的自文档性:好的类型名本身就是一种文档。
typedef 的常见用法详解
typedef 的强大之处在于它可以和各种数据类型结合使用。
为基本数据类型定义别名
这是最简单的用法,通常用于增加可读性。

typedef unsigned int uint; // 无符号整型 typedef unsigned char uchar; // 无字符型 typedef float real; // 实数 typedef long distance; // 距离
为数组类型定义别名
这非常实用,特别是对于多维数组和函数指针数组。
// 定义一个包含 10 个 int 元素的数组类型
typedef int INT_ARRAY_10[10];
int main() {
INT_ARRAY_10 arr1 = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
INT_ARRAY_10 arr2;
// arr1 和 arr2 都是包含 10 个 int 的数组
for (int i = 0; i < 10; i++) {
printf("%d ", arr1[i]);
}
printf("\n");
return 0;
}
为指针类型定义别名
这是 typedef 最常见的用途之一,可以极大地简化指针的声明。
a) 指向基本数据类型的指针
typedef int* IntPtr; // IntPtr 是一个指向 int 的指针类型
int main() {
int num = 100;
IntPtr p = # // 等价于 int* p = #
*p = 200;
printf("num = %d\n", num); // 输出 200
return 0;
}
b) 指向数组的指针
// 定义一个指向包含 5 个 int 的数组的指针类型
typedef int (*ARRAY_PTR_5)[5];
int main() {
int arr[5] = {10, 20, 30, 40, 50};
ARRAY_PTR_5 p = &arr; // p 是一个指向数组的指针
// 通过指针访问数组元素
printf("p[0][2] = %d\n", p[0][2]); // 输出 30
printf("(*p)[3] = %d\n", (*p)[3]); // 输出 40
return 0;
}
c) 指向函数的指针
这是 typedef 最强大也最容易让人困惑的用法,没有 typedef,声明一个函数指针会非常冗长和复杂。
// 定义一个函数指针类型,该指针指向一个返回 int,参数为两个 int 的函数
typedef int (*CalcFunc)(int, int);
// 加法函数
int add(int a, int b) {
return a + b;
}
// 减法函数
int subtract(int a, int b) {
return a - b;
}
int main() {
// 使用 CalcFunc 类型来声明函数指针变量
CalcFunc func_ptr;
func_ptr = add;
printf("10 + 5 = %d\n", func_ptr(10, 5)); // 输出 15
func_ptr = subtract;
printf("10 - 5 = %d\n", func_ptr(10, 5)); // 输出 5
return 0;
}
为结构体(struct)定义别名
这是 typedef 在结构体中的标准用法,可以避免每次使用结构体时都要写 struct 关键字。
先定义结构体,再用 typedef
struct Point {
int x;
int y;
};
// 为 struct Point 创建一个别名
typedef struct Point Point_t;
int main() {
Point_t p1; // 现在可以直接使用 Point_t 定义变量,无需 struct
p1.x = 10;
p1.y = 20;
printf("Point: (%d, %d)\n", p1.x, p1.y);
return 0;
}
在定义结构体时同时定义别名(更常用)
这是一种更简洁的写法,将 struct 和 typedef 合二为一。
// 注意:这里的 Point_t 是结构体类型的别名,而不是结构体标签
typedef struct {
int x;
int y;
} Point_t;
int main() {
Point_t p1;
p1.x = 10;
p1.y = 20;
printf("Point: (%d, %d)\n", p1.x, p1.y);
// 这种写法下,下面这句代码是错误的,因为没有结构体标签 "Point"
// struct Point p2; // Error: use of undeclared identifier 'Point'
return 0;
}
补充说明:如果你希望同时保留结构体标签和别名,可以这样写:
typedef struct Point {
int x;
int y;
} Point_t;
// 现在两种方式都可以使用
Point_t p1;
struct Point p2;
为联合体(union)定义别名
语法与结构体完全相同。
typedef union {
int i;
float f;
} DataUnion;
int main() {
DataUnion data;
data.i = 10;
printf("data.i = %d\n", data.i);
data.f = 3.14f;
printf("data.f = %f\n", data.f);
return 0;
}
typedef 与 #define 的区别
初学者很容易将 typedef 和 #define 混淆,因为它们都可以用来创建别名,但它们有本质的区别:
| 特性 | typedef |
#define |
|---|---|---|
| 本质 | 关键字,由编译器处理。 | 宏定义,由预处理器在编译前处理。 |
| 机制 | 为一个类型创建一个别名,是文本替换。 | 进行简单的文本替换,不做语法检查。 |
| 作用域 | 遵循 C 语言的作用域规则(如在函数内定义则只在该函数内有效)。 | 从定义处到文件结尾都有效,没有作用域概念。 |
| 类型处理 | 理解类型,能处理指针、数组等复杂类型。 | 不理解类型,只是机械地替换文本。 |
| 示例 | typedef int* IntPtr; |
#define IntPtr int* |
一个经典的 #define 陷阱:
#define PTR_INT int* // 这是一个宏定义 int a = 10, b = 20; // 预处理后,这行代码会变成:int* p1, p2; // p2 是一个 int 类型,而不是指针! PTR_INT p1, p2; // 正确的 typedef 写法 typedef int* IntPtr; IntPtr p3, p4; // p3 和 p4 都是指向 int 的指针
从这个例子可以看出,typedef 在处理指针等复杂类型时更安全、更可靠。
typedef 是 C 语言中一个非常有用的工具,它通过为现有类型创建别名,极大地提升了代码的可读性、简洁性和可维护性,无论是为基本类型、数组、指针还是自定义的结构体/联合体定义别名,typedef 都能发挥巨大作用,掌握 typedef,尤其是函数指针的 typedef,是迈向 C 语言高级编程的重要一步。
