## define vs typedef ## 判别规则(核心,唯一要记的) - 定义**常量 / 宏函数 / 条件编译** → 用 `#define`(文本替换,无类型) - 给**类型起别名** → 用 `typedef`(编译期真类型) 一句话:**"define 是复制粘贴,typedef 是起真名——粘贴会贴错,真名不会。"** ## 抽象描述(一句话本质) #define 是**预处理期**的纯文本替换——无类型、无作用域、无错误检查;typedef 是**编译期**给类型起真名——有类型、有作用域、有检查。 ## 正反例(建立直觉) - **正例1**:`#define MAX 100` 常量 + `typedef unsigned int u32;` 类型别名,各干各的 - **正例2(经典陷阱)**:`#define PINT int*` → `PINT a, b;` 文本替换成 `int* a, b;` → a 是指针、b 是普通 int - **正例3**:`typedef int* PINT2;` → `PINT2 c, d;` c 和 d 都是指针(真类型整行生效) - **反例1**:宏无类型检查:`#define ADD(a,b) a+b` → `ADD(1,2)*3` 展开成 `1+2*3=7`,不是 9(不会自动加括号) ## 易混对比 | | `#define` | `typedef` | | ------------ | ----------------------------------------------------- | --------------------------------------------- | | 处理阶段 | **预处理**(编译前,纯文本替换) | **编译期**(编译器认识真类型) | | 类型检查 | ❌ 无 | ✅ 有 | | 作用域 | ❌ 无(全局生效到 #undef) | ✅ 有(遵循代码作用域) | | 声明多个变量 | `PINT a,b;` → b 是 int,翻车 | `PINT2 c,d;` → 都是指针,安全 | | 典型用途 | 常量、宏函数、条件编译 `#ifdef`、头文件保护 `#ifndef` | 类型别名、结构体别名、固定宽度类型 `uint32_t` | ## 变体验证(3 题,全过=学会) 1. `#define MUL(a,b) a*b` → `MUL(2+3,4)` = `2+3*4` = **14**(宏不自动加括号) 2. 陷阱题:`typedef char* STR; STR s1,s2;` 与 `#define STR2 char*; STR2 s3,s4;` → **s4** 是 char,其余都是指针(`char* s3, s4;` 中 * 只粘 s3) 3. 结构体场景:`typedef struct { int x; } Point;` → 声明用 **`Point p;`**;带标签的 `struct Point { int x; };` → 用 `struct Point p;`;**匿名** `struct { int x; };` → 没法再声明新变量,只能定义处直接带变量名 ## 口述要点(面试怎么讲) - **结论先行**:宏 = 文本替换(无类型无检查),typedef = 真类型(有类型有检查) - **宏为什么不做类型检查/不加括号**:宏在**预处理阶段**就替换成纯文本,等真正做类型检查的编译器上场时宏**已经不存在了**——编译器只看到替换后的字符,没有任何"这是宏"的信息,优先级、类型错误全原样继承 - **必须用 #define 的场景**:条件编译 `#ifdef/#ifndef`、头文件重复包含保护——typedef 替代不了 - **uint32_t 的来源**(加分点):`` 里用 **typedef 定义的类型别名**,底层类型因平台而异(32 位平台是 `unsigned int`,16 位单片机可能是 `unsigned long`);`_t` 是 C 标准的**类型命名约定**(代表 type),凡 `_t` 结尾都是类型名(size_t、int16_t、uint32_t…)。嵌入式爱用是因为 C 基本类型字长随平台变,固定宽度类型让位操作和跨平台移植安全 - **易错点**:`#define PINT int*` 多变量声明翻车;匿名结构体无别名无法后续声明 ## 关系网络 | 相邻概念 | 和本主题的关系 | 孤立理解会犯的错 | | ------------ | ----------------------------------------------------------------- | -------------------------------------------- | | const | 宏常量 `#define MAX 100` 无类型;`const int MAX` 有类型、进只读段 | 以为宏能替代 const——查不出类型错、不进只读段 | | 内联函数 | 宏函数 vs 内联函数:宏无类型检查、有副作用风险,内联是真正的函数 | 以为宏函数能替代函数 | | struct/union | typedef 给结构体起别名,省 `struct` 关键字 | 以为匿名结构体也能被后续引用 | | 跨平台 | typedef + `_t` 约定封装固定宽度类型(uint32_t) | 直接用 `unsigned int`,平台一换就崩 | ## 学习日期 2026-08-03 --- _每主题一页,复习时只翻本目录。_