[资料干货] #define 和 typedef 有啥区别?从底层到应用一次讲清

[复制链接]
34|0
liao6 发表于 2026-11-2 10:28 | 显示全部楼层 |阅读模式
本帖最后由 liao6 于 2026-11-2 10:30 编辑

@21小跑堂 #申请原创# #技术资源#
@21小跑堂


简介
        很多人写 C 的第一周,就会同时碰上 #define 和 typedef。它们看起来都能“起个别名”,于是有人拿宏去代替类型,有人拿 typedef 去写常量,结果调试时一头雾水。其实两者根本不在同一层工作:一个在预处理里做字符串替换,一个在编译期里登记类型别名。把这层差别想清楚,后面很应用起来才会少踩坑。
一、编译流水线
        源文件进编译器之前,大体要经过:预处理 → 编译 → 汇编 → 链接。#define 在第一步执行,typedef 在第二步执行,两者在不同的阶段。
        预处理阶段,编译器还没开始“理解” C 语法。它只认以 # 开头的指令:展开 #include、处理条件编译、把宏名字换成对应文本。替换完,宏本身在源码里已经消失了,后面的编译器看到的是展开后的普通代码。
        编译阶段才开始词法分析、语法分析和语义分析。此时编译器建立符号表,知道每个标识符是变量、函数还是类型。typedef 就是在这里登记:告诉编译器,“这个名字在类型系统里等价于某某类型”。
         531376ae7f50573a5c.png
二、#define:预处理期的“找字替换”
最简单的例子:
#define MAX 100#define SQUARE(x) ((x) * (x))

                               
登录/注册后可看大图

预处理看到 MAX,就换成 100;看到 SQUARE(a+1),就换成 ((a+1) * (a+1))。注意括号:宏不会帮你算优先级,养成良好的编程规范,顺手就把括号给加上。
宏的强大之处在于它可以参数化,还能配合 #、## 做字符串化和拼接,条件编译里也离不开它。但代价同样明显:
没有类型,没有作用域。 宏是全局文本替换(从定义点到文件尾,或到 #undef),编译器不知道你想表达的是整数还是指针。报错信息往往指到展开之后的位置,读起来像天书。
经典陷阱是用宏“假装”定义指针类型:
#define PTR int*PTR a, b;   // 展开成:int* a, b;            // a 是 int*,b 是 int —— 不是你想的

                               
登录/注册后可看大图

         956016ae7f51665776.png
三、typedef:编译期的类型别名
换写法:
typedef int* Ptr;Ptr a, b;   // a、b 都是 int*

                               
登录/注册后可看大图

这里 Ptr 进入了类型系统。声明多个变量时,每个都按同一种类型解析,不会出现宏那种“只贴在第一个名字上”的尴尬。
再看一个更常见的用途——给复杂声明起短名:
typedef unsigned long long u64;typedef int (*CmpFn)(const void*, const void*);

                               
登录/注册后可看大图

函数指针声明本来就难读,typedef 之后,回调、表驱动代码会清爽很多。结构体上也常见:
typedef struct Node {    int val;    struct Node *next;} Node;

                               
登录/注册后可看大图

有两点要心里有数:

  • 别名不是新类型。 typedef int Length; 之后,Length 和 int 在类型检查上完全兼容,互相赋值不会报警。它不是 C++ 那种强类型包装。
  • 有作用域。 写在函数里的 typedef,出了函数就看不见;写在头文件里被 #include,才“看起来像全局”。
         222126ae7f526892ba.png
四、对照着记:本质差在“谁在干活”[td]               
         290566ae7f582096e5.png
        一句话口诀:宏改字,typedef 改名。 改字发生在编译器“睁眼”之前;改名发生在编译器已经开始认类型之后。
         923936ae7f534c375f.png
五、总结
一句话总结:#define 是预处理阶段的简单文本替换(预处理指令,和编译器语法、类型系统无关); typedef 是编译阶段语义层面的类型别名(属于 C 语言关键字,交给语义分析器处理,是类型系统的一部分)。
​





您需要登录后才可以回帖 登录 | 注册

本版积分规则

730

主题

1311

帖子

3

粉丝
快速回复 在线客服 返回列表 返回顶部