typedef
typedef 是 C 语言中用来给 现有数据类型 起 “别名” (Nickname) 的关键字。
如果说 #define 是简单的“查找替换”,那么 typedef 就是合法的“户口更名”。编译器是真正承认这个新名字的。
它的核心作用就是:让复杂的类型名字变短,让人类更容易看懂。
我们分三个场景来看它的威力:
1. 场景一:偷懒神器 (基本类型)
在单片机开发中,我们经常要写 unsigned char(无符号字符型,0~255)。 这就好比一个人的名字叫“尼古拉斯·赵四”,太长了,写着累。
使用 typedef 起别名:
C
// 给 unsigned char 起个别名叫 u8
typedef unsigned char u8;
// 以后写代码:
u8 data = 10; // 等同于 unsigned char data = 10;STM32 中的经典应用: 你是不是经常在代码里看到 uint8_t, uint16_t, uint32_t? 这并不是 C 语言原本就有的关键字,它们其实全都是 typedef 出来的!
在 stdint.h 头文件里,写着:
C
typedef unsigned char uint8_t; // 8位无符号整数 (1字节)
typedef unsigned short uint16_t; // 16位无符号整数 (2字节)
typedef unsigned int uint32_t; // 32位无符号整数 (4字节)好处: 一眼就能看出这个变量占几个字节,比写 int 或 long 清楚多了(不同编译器下 int 长度可能不同,但 uint32_t 永远是 32 位)。
2. 场景二:结构体救星 (STM32 最常用)
这是 typedef 最重要的用途。
如果不使用 typedef,定义一个结构体变量非常麻烦,必须每次都带上 struct 关键字。
没有 typedef 时 (很啰嗦):
C
struct Student {
int id;
int age;
};
// 定义变量时必须加 struct
struct Student xiaoming;
struct Student xiaohong;使用 typedef 后 (很清爽):
C
// 语法:typedef 原类型名 新别名;
typedef struct {
int id;
int age;
} Student_t; // Student_t 就是这个结构体的别名
// 定义变量时,不用加 struct 了!
Student_t xiaoming;
Student_t xiaohong;STM32 库函数就是这么干的: 你常用的 GPIO_InitTypeDef 其实就是一个被 typedef 过的结构体别名。
C
// stm32f10x_gpio.h 里的源码大概是这样的:
typedef struct
{
uint16_t GPIO_Pin;
GPIOSpeed_TypeDef GPIO_Speed;
GPIOMode_TypeDef GPIO_Mode;
} GPIO_InitTypeDef; // 别名
// 所以你能直接写:
GPIO_InitTypeDef GPIO_InitStructure;3. 场景三:typedef vs #define (面试陷阱)
这是最容易搞混的地方。虽然它们都能起别名,但在处理指针时,区别巨大。
案例:我想定义一个“指向 int 的指针”类型。
C
#define PTR_D int* // 宏定义方式
typedef int* ptr_t; // typedef 方式测试代码:
C
PTR_D a, b; // 宏展开后变成:int* a, b;
ptr_t x, y; // 真正定义:x 和 y 都是指针结果:
- 宏定义 (
#define):是纯文本替换。int* a, b;实际上等价于int *a; int b;- a 是指针,b 只是个普通的整数! (这就出 Bug 了)
typedef:是类型封装。- 编译器知道
ptr_t就是一种指针类型。 - x 是指针,y 也是指针! (这是我们要的)
- 编译器知道
总结
- 语法:
typedef 旧名字 新名字;(注意结尾有分号!) - 作用: 给数据类型起外号,让代码更短、更易读。
- STM32 里的体现:
uint8_t代替unsigned char。GPIO_InitTypeDef代替struct ...。
- 原则:
- 如果是给数字常量起名(如
3.14),用#define。 - 如果是给数据类型起名(如
struct),必须用typedef。
- 如果是给数字常量起名(如