写代码最烦的就是长类型名。typedef 就是干这个的:给已有类型起个短一点、更贴切的新名字(别名)。结构体、指针、数组这些复杂声明,一下子好读很多。

先看最直接的例子

给 int 起个别名:

typedef int Integer;

int main() {
    Integer n = 10;     /* n 还是 int,但写起来更像业务语言 */
    printf("%d", n);    // 10
    return 0;
}

语法就一句话:

typedef 已有类型 新名字;

声明完,新名字就能当原来的类型用了。

给内置类型起别名

长整型的 long long 每次写都嫌长,比赛和算法代码里常缩写:

typedef long long ll;

int main() {
    ll a = 20;
    printf("%lld", a);   // 20
    return 0;
}

给结构体起别名

这是 typedef 最经典的用法。不用 typedef:

struct Students {
    char name[50];
    int ID_no;
};

struct Students s;    /* 每次都要带 struct 关键字 */

用了 typedef:

typedef struct Students {
    char name[50];
    int ID_no;
} stu;                 /* stu 就是这个结构体的别名 */

int main() {
    stu s;             /* 干净利落,不用写 struct */
    s.ID_no = 108;
    return 0;
}

甚至可以把 struct 标签都省掉,直接匿名 + typedef:

typedef struct {
    char name[50];
    int ID_no;
} stu;   /* 以后就用 stu,标签没必要存在 */

给指针起别名

typedef int* ip;

int main() {
    int a = 10;
    ip ptr = &a;       /* ptr 是 int* */
    printf("%d", *ptr); // 10
    return 0;
}

给数组起别名

typedef int arr[4];    /* arr 是"int[4]"的别名 */

int main() {
    arr a = { 10, 20, 30, 40 };   /* 一个 int[4] 数组 */
    for (int i = 0; i < 4; i++)
        printf("%d ", a[i]);      // 10 20 30 40
    return 0;
}

函数指针这类更绕的声明也能 typedef 化简(函数指针篇里那种写法,用 typedef 收起来会清爽得多)。

typedef 和 #define 的区别

typedef#define
由编译器处理预处理器做纯文本替换
作用于类型,类型检查友好任何文本都能替换,不做类型检查
可以在局部作用域声明文件级生效,容易误伤
不能用来写代码片段/带参替换可以做函数式宏

一个经典坑:#define 声明指针别名时只替换文本。

#define intptr int*    /* 危险写法 */
intptr a, b;           /* 等价于 int* a, b;  ,b 其实是 int,不是指针! */

typedef int* intptr2;
intptr2 c, d;          /* c、d 都是 int*,类型安全 */

这就是为什么给类型起别名,优先用 typedef。

什么时候用 typedef

  • 结构体、共用体这类"每次写都带 struct"的长类型。
  • 复杂指针、函数指针、数组类型,把声明收成好读的短名。
  • 需要统一的跨平台类型(比如 uint32_t 这种约定俗成的风格)。

让类型名读起来像业务词汇,而不是一堆符号堆叠,读你代码的人(包括未来的你)会感谢这个选择。