C语言 typedef 和 #define 有什么区别?指针声明陷阱详解
typedef 是编译器层面的类型别名,#define 是预处理器层面的文本替换——一个在编译时做类型检查,一个在编译前做字符串替换,这是最根本的区别。
最经典的面试陷阱:连续声明指针时结果不同。typedef char* PCHAR; PCHAR a, b; 中 a 和 b 都是指针;而 #define PCHAR char*; PCHAR a, b; 展开后变成 char* a, b;,只有 a 是指针,b 是普通 char——这个 bug 编译器不会报错,能让你查半天。
另一个容易踩的坑:宏函数的副作用。#define SQUARE(x) ((x) * (x)) 传入 SQUARE(i++) 会导致 i 自增两次,而 typedef 不存在这个问题,因为它只管类型不管值。
c// 连续声明:typedef 安全,#define 不安全 typedef char* PCHAR; PCHAR a, b; // a 和 b 都是 char* #define PCHAR2 char* PCHAR2 c, d; // c 是 char*,d 是 char!
一条原则:需要类型别名的用 typedef,需要文本替换的用 #define。函数指针、结构体、跨平台类型定义必须用 typedef;常量定义、条件编译、简单宏函数用 #define。
追问
typedef 和 #define 在函数指针定义上有什么区别?
typedef 写出来可读性强得多:typedef int (*Callback)(int, int); 之后直接用 Callback cb = my_func;。用 #define 的话 #define Callback int (*)(int, int) 看着就像函数声明,而且 Callback cb, cb2; 同样只有第一个是指针。函数指针定义是 typedef 最不可替代的场景。
#define 定义的常量为什么没有类型安全?
因为 #define 在预处理阶段就被替换掉了,编译器根本看不到宏名。#define MAX 100 之后代码里出现的是裸数字 100,编译器不知道你原来写了 MAX,也不知道你想让它是什么类型——int、long 还是 unsigned 全靠上下文推断。而 const int MAX = 100; 或 typedef enum { MAX = 100 } 都有明确的类型。
typedef 能不能和存储类说明符一起用?
不能。typedef static int MyInt; 是非法的——typedef 是存储类说明符的一种,和 static、extern 互斥。这是 C 标准明确规定的,编译器会直接报错。同理 typedef extern int X; 也不行。
实际项目里 typedef 最常见的用法是什么?
三个场景:(1) 给 unsigned long long 之类的长类型起短名,比如 typedef uint64_t u64;(2) 定义回调/函数指针类型,让函数签名可读;(3) 跨平台抽象——typedef long intptr_t 在 64 位 Linux 上,typedef __int64 intptr_t 在 Windows 上,业务代码统一用 intptr_t 不用关心底层。