typedef 為關鍵字,為既有資料型別(內建/自訂)建立別名。主要目的:
typedef long int32;)。typedef struct tagNode {
char *pItem;
pNode pNext; // 錯誤:pNode 尚未定義完成
} *pNode;
原因:typedef 別名在結構體定義結束後才生效,結構體內無法使用該別名。
// 1. 使用標籤名
typedef struct tagNode {
char *pItem;
struct tagNode *pNext;
} *pNode;
// 2. 先前向宣告別名
typedef struct tagNode *pNode;
struct tagNode {
char *pItem;
pNode pNext;
};
// 3. 規範做法:分離結構定義與別名
struct tagNode {
char *pItem;
struct tagNode *pNext;
};
typedef struct tagNode *pNode;
typedef char *pStr1;
#define pStr2 char *
pStr1 s1, s2; // 皆為 char*
pStr2 s3, s4; // s3=char*, s4=char !
#define 只是文字替換,pStr2 s3, s4 展開為 char *s3, s4,s4 變成 char。typedef 在型別系統層面運作,pStr1 是完整型別,宣告多個變數皆為指標。
typedef char *pStr;
const pStr p2; // 等價於 char * const p2(指標本身唯讀)
// 非 const char *p2(指向內容唯讀)
const 修飾的是 pStr 這個完整型別(指標),而非 char。這再次證明 typedef 非單純文字替換。
| 特性 | #define | typedef |
|---|---|---|
| 條件編譯 | 支援 #ifdef/#undef | 不支援 |
| 作用域 | 無(全域文本替換) | 遵循區塊/檔案作用域 |
| 型別安全 | 無 | 編譯器檢查 |
| 除錯可見性 | 符號表不可見 | 符號表可見 |
原則:型別別名用 typedef,常數/條件編譯用 #define。
步驟:在原宣告中以別名取代變數名,前加 typedef。
// 原:int *(*a[5])(int, char*);
typedef int *(*pFun)(int, char*);
pFun a[5];
// 原:void (*b[10])(void (*)());
typedef void (*pFunParam)();
typedef void (*pFun)(pFunParam);
pFun b[10];
// 原:double (*)() (*pa)[9];
typedef double (*pFun)();
typedef pFun (*pFunParam)[9];
pFunParam pa;
cdecl 呼叫慣例與函數指標轉型涉及跨模組回呼時,確保函數指標型別包含呼叫慣例(__stdcall, __cdecl),避免參數堆疊錯亂。
typedef 建立真正的型別別名,語義清晰、型別安全、支援作用域。struct tag 定義與 typedef,避免前向參考錯誤。typedef 分層拆解,提升可讀性與維護性。#define 定義型別,特別是涉及指標時。善用 typedef 是寫出專業級 C 程式碼的關鍵習慣之一。