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 作用位置藏在指针别名中。

五、快速记忆

  1. 类型别名用 typedef,文本替换用 #define。
  2. typedef int *P; P a, b;:两个都是指针。
  3. #define P int * 后写 P a, b;:只有 a 是指针。
  4. const IntPtr = int *const:锁指向,不锁目标值。
  5. const int *:允许改指向,不允许通过该指针改目标值。

本节为第 18 篇独立笔记。第 19 篇留给下一项真正的新知识。