18 typedef 与宏定义的类型区别
一、核心结论
typedef 给完整类型起别名;#define 只做预处理文本替换。
| 对比 | typedef | #define |
|---|---|---|
| 本质 | 声明类型别名 | 替换源码文本 |
| 指针声明 | 别名包含完整指针类型 | * 仍按每个声明符分别解释 |
| 推荐用途 | 类型别名、回调类型、结构体类型 | 宏常量、条件编译、简单宏 |
例子:两个变量是否都是指针?
typedef int *IntPtr;
IntPtr a, b; // a 和 b 都是 int *
#define PTR int *
PTR a, b; // 展开为 int *a, b;
// a 是 int *,b 是 int
typedef IntPtr 宏 PTR
┌───────┬───────┐ ┌───────┬───────┐
│ a:int*│ b:int*│ │ a:int*│ b:int │
└───────┴───────┘ └───────┴───────┘
二、重点陷阱:const IntPtr 是什么?
typedef int *IntPtr;
int x = 10, y = 20;
const IntPtr p = &x; // 相当于 int *const p
*p = 30; // 正确:可以修改 x
// p = &y; // 错误:不能修改 p 保存的地址
注意:typedef 不是宏替换,不能把 const IntPtr 简单按字符替换成 const int *。
二极管对比
| 声明 | 能改变指针指向? | 能通过该指针改变目标整数? |
|---|---|---|
const IntPtr p = &x; | ❌ | ✅ |
const int *q = &x; | ✅ | ❌ |
const IntPtr p const int *q
┌────────────────┐ ┌────────────────┐
│ p:指向固定 🔒 │ │ q:可以改指向 │
└───────┬────────┘ └───────┬────────┘
↓ ↓
┌────────────────┐ ┌────────────────┐
│ x:允许通过*p改 │ │ 不能通过*q修改 │
└────────────────┘ └────────────────┘
这里“固定”是类型限制,不是 RTOS 锁;const int *q 不代表目标对象绝对不可修改,只表示不能通过 q 修改。
三、完整 C 代码
#include <stdio.h>
typedef int *IntPtr;
int main(void)
{
int x = 10, y = 20;
const IntPtr p = &x;
const int *q = &x;
*p = 30; // p 指向固定,但可写 x
q = &y; // q 可以重新指向 y
printf("%d %d\n", x, *q); // 30 20
return 0;
}
四、蓝牙/TWS 固件应用
固件里可以用 typedef 给事件回调、缓冲区指针、结构体等类型起清晰名字;宏仍用于配置开关和常量。对于只读缓冲区接口,优先直接写清楚 const uint8_t *data,避免把 const 作用位置藏在指针别名中。
五、快速记忆
- 类型别名用
typedef,文本替换用#define。 typedef int *P; P a, b;:两个都是指针。#define P int *后写P a, b;:只有a是指针。const IntPtr=int *const:锁指向,不锁目标值。const int *:允许改指向,不允许通过该指针改目标值。
本节为第 18 篇独立笔记。第 19 篇留给下一项真正的新知识。