typedef的用法有:1、為基本資料型別定義新的型別名稱;2、為自訂資料型別(結構體、共用體和枚舉型別)定義簡潔的型別名稱;3、為陣列定義簡潔的型別名稱;4、為指標定義簡潔的名稱。
C語言允許使用者使用typedef 關鍵字來定義自己習慣的資料型別名稱,來取代系統預設的基本型別名稱、陣列型別名稱、指標型名稱與使用者自訂的結構型名稱、共用型名稱、枚舉型名稱等。
一旦使用者在程式中定義了自己的資料型別名稱,就可以在程式中用自己的資料型別名稱來定義變數的型別、陣列的型別、指標變數的型別與函數的型別等。
例如,C 語言在C99 之前並未提供布林類型,但我們可以使用typedef 關鍵字來定義一個簡單的布林類型,如下面的程式碼所示:
typedef int BOOL; #define TRUE 1 #define FALSE 0
定義好之後,就可以像使用基本型別資料一樣使用它了,如下面的程式碼所示:
BOOL bflag=TRUE;
#typedef的4種用法
在實際使用中,typedef 的應用主要有以下4種。
1、為基本資料型別定義新的型別名
也就是說,系統預設的所有基本型別都可以利用typedef 關鍵字來重新定義型別名,範例程式碼如下所示:
typedef unsigned int COUNT;
而且,我們也可以使用這種方法來定義與平台無關的類型。例如,要定義一個叫REAL 的浮點類型,在目標平台一上,讓它表示最高精度的類型,即:
typedef long double REAL;
在不支援long double 的平台二上,改為:
typedef double REAL;
甚至還可以在連double 都不支援的平台三上,改為:
typedef float REAL;
這樣,當跨平台移植程式時,我們只需要修改一下typedef 的定義即可,而不用對其他原始碼做任何修改。其實,標準庫中廣泛地使用了這個技巧,例如size_t 在VC 2010 的crtdefs.h 檔案中的定義如下所示:
#ifndef _SIZE_T_DEFINED #ifdef _WIN64 typedef unsigned __int64 size_t; #else typedef _W64 unsigned int size_t; #endif #define _SIZE_T_DEFINED #endif
2、為自訂資料類型(結構體、共用體和枚舉型別)定義簡潔的型別名稱
以結構體為例,下面我們定義一個名為Point 的結構體:
struct Point { double x; double y; double z; };
在呼叫這個結構體時,我們必須像下面的程式碼這樣來呼叫這個結構體:
struct Point oPoint1={100,100,0}; struct Point oPoint2;
在這裡,結構體struct Point 為新的資料型別,在定義變數的時候均要向上面的呼叫方法一樣有保留字struct,而不能像int 和double 那樣直接使用Point 來定義變數。現在,我們利用typedef 定義這個結構體,如下面的程式碼所示:
typedef struct tagPoint { double x; double y; double z; } Point;
在上面的程式碼中,實際上完成了兩個動作:
1)、定義了一個新的結構類型,程式碼如下所示:
struct tagPoint { double x; double y; double z; } ;
其中,struct 關鍵字和tagPoint 一起構成了這個結構類型,無論是否存在typedef 關鍵字,這個結構都存在。
2)、使用typedef 為這個新的結構起了一個別名,叫Point,即:
typedef struct tagPoint Point
因此,現在你就可以像int 和double 那樣直接使用Point 定義變量,如下面的程式碼所示:
Point oPoint1={100,100,0}; Point oPoint2;
為了加深對typedef 的理解,我們再來看一個結構體例子,如下面的程式碼所示:
typedef struct tagNode { char *pItem; pNode pNext; } *pNode;
從表面上看,上面的範例程式碼與前面的定義方法相同,所以應該沒有什麼問題。但是編譯器卻報了一個錯誤,為什麼呢?莫非 C 語言不允許在結構中包含指向它自己的指標?
其實問題並非在於struct 定義的本身,大家應該都知道,C 語言是允許在結構中包含指向它自己的指標的,我們可以在建立鍊錶等資料結構的實作上看到很多這類別例子。那問題在哪裡呢?其實,根本問題還是在於 typedef 的應用。
在上面的程式碼中,新結構建立的過程中遇到了 pNext 聲明,其類型是 pNode。這裡要特別注意的是,pNode 表示的是該結構體的新別名。於是問題出現了,在結構體類型本身還沒有建立完成的時候,編譯器根本就不認識 pNode,因為這個結構體類型的新別名還不存在,所以自然就會報錯。因此,我們要做一些適當的調整,例如將結構體中的pNext 宣告修改成如下方式:
typedef struct tagNode { char *pItem; struct tagNode *pNext; } *pNode;
或將struct 與typedef 分開定義,如下面的程式碼所示:
typedef struct tagNode *pNode; struct tagNode { char *pItem; pNode pNext; };
在上面的程式碼中,我們同樣使用typedef 給一個還未完全宣告的型別tagNode 起了一個新別名。不過,雖然 C 語言編譯器完全支援這種做法,但不建議這樣做。建議還是使用以下規範定義方法:
struct tagNode { char *pItem; struct tagNode *pNext; }; typedef struct tagNode *pNode;
3、为数组定义简洁的类型名称
它的定义方法很简单,与为基本数据类型定义新的别名方法一样,示例代码如下所示:
typedef int INT_ARRAY_100[100]; INT_ARRAY_100 arr;
4、为指针定义简洁的名称
对于指针,我们同样可以使用下面的方式来定义一个新的别名:
typedef char* PCHAR; PCHAR pa;
对于上面这种简单的变量声明,使用 typedef 来定义一个新的别名或许会感觉意义不大,但在比较复杂的变量声明中,typedef 的优势马上就体现出来了,如下面的示例代码所示:
int *(*a[5])(int,char*);
对于上面变量的声明,如果我们使用 typdef 来给它定义一个别名,这会非常有意义,如下面的代码所示:
// PFun是我们创建的一个类型别名 typedef int *(*PFun)(int,char*); // 使用定义的新类型来声明对象,等价于int*(*a[5])(int,char*); PFun a[5];
小心使用 typedef 带来的陷阱
接下来看一个简单的 typedef 使用示例,如下面的代码所示:
typedef char* PCHAR; int strcmp(const PCHAR,const PCHAR);
在上面的代码中,“const PCHAR” 是否相当于 “const char*” 呢?
答案是否定的,原因很简单,typedef 是用来定义一种类型的新别名的,它不同于宏,不是简单的字符串替换。因此,“const PCHAR”中的 const 给予了整个指针本身常量性,也就是形成了常量指针“char*const(一个指向char的常量指针)”。即它实际上相当于“char*const”,而不是“const char*(指向常量 char 的指针)”。当然,要想让 const PCHAR 相当于 const char* 也很容易,如下面的代码所示:
typedef const char* PCHAR; int strcmp(PCHAR, PCHAR);
其实,无论什么时候,只要为指针声明 typedef,那么就应该在最终的 typedef 名称中加一个 const,以使得该指针本身是常量。
还需要特别注意的是,虽然 typedef 并不真正影响对象的存储特性,但在语法上它还是一个存储类的关键字,就像 auto、extern、static 和 register 等关键字一样。因此,像下面这种声明方式是不可行的:
typedef static int INT_STATIC;
不可行的原因是不能声明多个存储类关键字,由于 typedef 已经占据了存储类关键字的位置,因此,在 typedef 声明中就不能够再使用 static 或任何其他存储类关键字了。当然,编译器也会报错,如在 VC++2010 中的报错信息为“无法指定多个存储类”。
相关推荐:《c语言教程》
以上是C語言中typedef的用法有哪些?的詳細內容。更多資訊請關注PHP中文網其他相關文章!