C 語言允許開發者為現有的資料類型定義一個新的別名,這就像是給變數起個「綽號」一樣。引入別名的目的並非為了提升程式執行效率,而是為了讓編碼過程更加便捷、閱讀更清晰。
以結構體為例,假設結構體標籤名為 stu,在定義變數時必須寫成 struct stu stu1;。這裡的 struct 關鍵字顯得贅餘,但若省略又會導致編譯錯誤。若能為 struct stu 起一個別名 STU,定義變數便簡化為 STU stu1;,語法更精簡、語意更明確。這種做法在標準頭檔與實際專案開發中極為常見。
使用關鍵字 typedef 即可為類型建立別名,語法格式如下:
typedef 舊類型名 新類型名;
其中「舊類型名」是類型原本的名稱,「新類型名」是自訂的別名。例如:
typedef int INTEGER; INTEGER a, b; a = 1; b = 2;
INTEGER a, b; 等效於 int a, b;。
typedef char ARRAY20[20];
ARRAY20 代表 char[20] 類型,即長度為 20 的字元陣列。之後可直接用 ARRAY20 宣告陣列:
ARRAY20 a1, a2, s1, s2;
等價於:
char a1[20], a2[20], s1[20], s2[20];
注意:陣列本身也有類型,char a1[20] 中 a1 的類型即為 char[20]。
typedef struct stu {
char name[20];
int age;
char sex;
} STU;
STU 成為 struct stu 的別名,定義變數時可寫:
STU body1, body2;
等價於 struct stu body1, body2;。
typedef int (*PTR_TO_ARR)[4];
PTR_TO_ARR 是 int (*)[4](指向含 4 個 int 元素陣列的指標)的別名。使用方式:
PTR_TO_ARR p1, p2;
同理,函數指標也可定義別名:
typedef int (*PTR_TO_FUNC)(int, int); PTR_TO_FUNC pfunc;
#include <stdio.h>
typedef char (*PTR_TO_ARR)[30];
typedef int (*PTR_TO_FUNC)(int, int);
int max(int a, int b) {
return a > b ? a : b;
}
char str[3][30] = {
"https://c.biancheng.net",
"C語言中文網",
"C-Language"
};
int main() {
PTR_TO_ARR parr = str;
PTR_TO_FUNC pfunc = max;
int i;
printf("max: %d\n", (*pfunc)(10, 20));
for (i = 0; i < 3; i++) {
printf("str[%d]: %s\n", i, *(parr + i));
}
return 0;
}
執行結果:
max: 20 str[0]: https://c.biancheng.net str[1]: C語言中文網 str[2]: C-Language
務必理解:typedef 僅為現有類型起一個新名字,並不會創造出新的資料類型。為了「見名知意」,建議使用語意清晰的識別符,並採用全大寫命名慣例。
雖然 typedef 在表現上有時類似 #define,但兩者本質不同。正確的思考方式是將 typedef 視為一種「封裝」類型,宣告後無法再向其中添加其他修飾符。
#define INTERGE int unsigned INTERGE n; // 正常,宏展開為 unsigned int n; typedef int INTERGE; unsigned INTERGE n; // 錯誤,不能在 INTERGE 前加 unsigned
#define PTR_INT int * PTR_INT p1, p2; // 宏展開後:int *p1, p2; → p1 是指標,p2 是整數,類型不同! typedef int *PTR_INT; PTR_INT p1, p2; // p1、p2 皆為 int* 類型,類型一致
這正是 typedef 在處理複合類型(如指標)時展現優勢的關鍵所在。