5.define-vs-typedef.md 4.0 KB

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
  • 正例3typedef int* PINT2;PINT2 c, d; c 和 d 都是指针(真类型整行生效)
  • 反例1:宏无类型检查:#define ADD(a,b) a+bADD(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*bMUL(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 的来源(加分点):<stdint.h> 里用 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


每主题一页,复习时只翻本目录。