C語言中typedef用法(ZZ)
1.基本解釋
typedef爲C語言的關鍵字,做用是爲一種數據類型定義一個新名字。這裏的數據類型包括內部數據類型(int,char等)和自定義的數據類型(struct等)。
在編程中使用typedef目的通常有兩個,一個是給變量一個易記且意義明確的
新名字(別名),另外一個是
簡化一些比較複雜的類型聲明。
至於typedef有什麼微妙之處,請你接着看下面對幾個問題的具體闡述。
2. typedef & 結構的問題
當用下面的代碼定義一個結構時,編譯器報了一個錯誤,爲何呢?莫非C語言不容許在結構中包含指向它本身的指針嗎?請你先猜測一下,而後看下文說明:
typedef struct tagNode
{
char *pItem;
pNode pNext;
} *pNode;
答案與分析:
一、typedef的最簡單使用
typedef long byte_4;
給已知數據類型long起個新名字,叫byte_4。
二、 typedef與結構結合使用
typedef struct tagMyStruct
{
int iNum;
long lLength;
} MyStruct;
這語句實際上完成兩個操做:
1) 定義一個新的結構類型
struct tagMyStruct
{
int iNum;
long lLength;
};
分析:tagMyStruct稱爲「tag」,即「標籤」,其實是一個臨時名字,struct 關鍵字和tagMyStruct一塊兒,構成了這個結構類型,不管是否有typedef,這個結構都存在。
咱們能夠用struct tagMyStruct varName來定義變量,但要注意,使用tagMyStruct varName來定義變量是不對的,由於struct 和tagMyStruct合在一塊兒才能表示一個結構類型。
2) typedef爲這個新的結構起了一個名字,叫MyStruct。
typedef struct tagMyStruct MyStruct;
所以,MyStruct實際上至關於struct tagMyStruct,咱們可使用MyStruct varName來定義變量。
答案與分析
C語言固然容許在結構中包含指向它本身的指針,咱們能夠在創建鏈表等數據結構的實現上看到無數這樣的例子,上述代碼的根本問題在於typedef的應用。
根據咱們上面的闡述能夠知道:新結構創建的過程當中遇到了pNext域的聲明,類型是pNode,要知道pNode表示的是類型的新名字,那麼在類型自己尚未創建完成的時候,這個類型的新名字也還不存在,也就是說這個時候編譯器根本不認識pNode。
解決這個問題的方法有多種:
1)、
typedef struct tagNode
{
char *pItem;
struct tagNode *pNext;
} *pNode;
2)、
typedef struct tagNode *pNode;
struct tagNode
{
char *pItem;
pNode pNext;
};
注意:在這個例子中,你用typedef給一個還未徹底聲明的類型起新名字。C語言編譯器支持這種作法。
3)、規範作法:
struct tagNode
{
char *pItem;
struct tagNode *pNext;
};
typedef struct tagNode *pNode;
3. typedef & #define的問題
有下面兩種定義pStr數據類型的方法,二者有什麼不一樣?哪種更好一點?
typedef char *pStr;
#define pStr char *;
答案與分析:
一般講,typedef要比#define要好,特別是在有指針的場合。請看例子:
typedef char *pStr1;
#define pStr2 char *;
pStr1 s1, s2;
pStr2 s3, s4;
在上述的變量定義中,s一、s二、s3都被定義爲char *,而s4則定義成了char,不是咱們所預期的指針變量,根本緣由就在於#define只是簡單的字符串替換而typedef則是爲一個類型起新名字。
#define用法例子:
#define f(x) x*x
main( )
{
int a=6,b=2,c;
c=f(a) / f(b);
printf("%d \\n",c);
}
如下程序的輸出結果是: 36。
由於如此緣由,在許多C語言編程規範中提到使用#define定義時,若是定義中包含表達式,必須使用括號,則上述定義應該以下定義纔對:
#define f(x) (x*x)
固然,若是你使用typedef就沒有這樣的問題。
4. typedef & #define的另外一例
下面的代碼中編譯器會報一個錯誤,你知道是哪一個語句錯了嗎?
typedef char * pStr;
char string[4] = "abc";
const char *p1 = string;
const pStr p2 = string;
p1++;
p2++;
答案與分析:
是p2++出錯了。這個問題再一次提醒咱們:typedef和#define不一樣,它不是簡單的文本替換。上述代碼中const pStr p2並不等於const char * p2。const pStr p2和const long x本質上沒有區別,都是對變量進行只讀限制,只不過此處變量p2的數據類型是咱們本身定義的而不是系統固有類型而已。所以,const pStr p2的含義是:限定數據類型爲char *的變量p2爲只讀,所以p2++錯誤。
#define與typedef引伸談 1) #define宏定義有一個特別的長處:可使用 #ifdef ,#ifndef等來進行邏輯判斷,還可使用#undef來取消定義。 2) typedef也有一個特別的長處:它符合範圍規則,使用typedef定義的變量類型其做用範圍限制在所定義的函數或者文件內(取決於此變量定義的位置),而宏定義則沒有這種特性。 5. typedef & 複雜的變量聲明 在編程實踐中,尤爲是看別人代碼的時候,經常會遇到比較複雜的變量聲明,使用typedef做簡化自有其價值,好比: 下面是三個變量的聲明,我想使用typdef分別給它們定義一個別名,請問該如何作? >1:int *(*a[5])(int, char*); >2:void (*b[10]) (void (*)()); >3. double(*)() (*pa)[9]; 答案與分析: 對複雜變量創建一個類型別名的方法很簡單,你只要在傳統的變量聲明表達式裏用類型名替代變量名,而後把關鍵字typedef加在該語句的開頭就好了。 >1:int *(*a[5])(int, char*); //pFun是咱們建的一個類型別名 typedef int *(*pFun)(int, char*); //使用定義的新類型來聲明對象,等價於int* (*a[5])(int, char*); pFun a[5]; >2:void (*b[10]) (void (*)()); //首先爲上面表達式藍色部分聲明一個新類型 typedef void (*pFunParam)(); //總體聲明一個新類型 typedef void (*pFun)(pFunParam); //使用定義的新類型來聲明對象,等價於void (*b[10]) (void (*)()); pFun b[10]; >3. double(*(*pa)[9])(); //首先爲上面表達式藍色部分聲明一個新類型 typedef double(*pFun)(); //總體聲明一個新類型 typedef pFun (*pFunParam)[9]; //使用定義的新類型來聲明對象,等價於double(*(*pa)[9])(); pFunParam pa;