C語言typedef關鍵字

來源:互聯網
上載者:User
C語言typedef關鍵字

關於馬甲的笑話。有這樣一個笑話:一個獵人在河邊抓捕一條蛇,蛇逃進了水裡。過一會,一個烏龜爬到岸邊。獵人一把抓住這個烏龜,大聲的說道:小樣,別你為你穿了個馬甲我就不認識你了!
typedef 關鍵字是個偉大的縫紉師,擅長做馬甲,任何東西穿上這個馬甲就立馬變樣。它可以把狼變成一頭羊,也能把羊變成一頭狼。甚至還可以把長著翅膀的鳥人變成天使,同樣也能把美麗的天使變成鳥人。所以,你千萬不要得罪它,一定要掌握它的脾氣,不然哪天我把你當鳥人,你可別怪我。O(∩_∩)O~

一、曆史的誤會——也許應該是typerename。

很多人認為typedef 是定義新的資料類型,這可能與這個關鍵字有關。本來嘛,type 是資料類型的意思;def(ine)是定義的意思,合起來就是定義資料類型啦。不過很遺憾,這種理解是不正確的。也許這個關鍵字該被替換為“typerename”或是別的詞。
typedef 的真正意思是給一個已經存在的資料類型(注意:是類型不是變數)取一個別名,而非定義一個新的資料類型。比如:華美絕倫的芍藥,就有個別名---“將離”。中國古代男女交往,往往以芍藥相贈,表達惜別之情,送芍藥就意味著即將分離。所以文人墨客就給芍藥取了個意味深長的別名-----“將離”。這個新的名字就表達了那種依依不捨的惜別之情…這樣新的名字與原來的名字相比,就更能表達出想要表達的意思。

在實際項目中,為了方便,可能很多資料類型(尤其是結構體之類的自訂資料類型)需要我們重新取一個適用實際情況的別名。這時候typedef 就可以協助我們。例如:

typedef struct student
{
//code
}Stu_st,*Stu_pst;
A)struct student stu1;和Stu_st stu1;沒有區別。
B)struct student *stu2;和Stu_pst stu2;和Stu_st *stu2;沒有區別。


這個地方很多初學者迷惑,B)的兩個定義為什麼相等呢?其實很好理解。我們把“struct student { /*code*/}”看成一個整體,typedef 就是給“struct student {/*code*/}”取了個別名叫“Stu_st”;同時給“struct student { /*code*/} *”取了個別名叫“Stu_pst”。只不過這兩個名字同時取而已,好比你給你家小狗取了個別名叫“大黃”,同時你妹妹給小狗帶了小帽子,然後給它取了個別名叫“小可愛”。^_^。

不管實在C還是C++代碼中,typedef這個詞都不少見,當然出現頻率較高的還是在C代碼中。typedef與#define有些相似,但更多的是不同,特別是在一些複雜的用法上,就完全不同了,看了網上一些C/C++的學習者的部落格,其中有一篇關於typedef的總結還是很不錯,由於總結的很好,我就不加修改的引用過來了。

用途一:

定義一種類型的別名,而不只是簡單的宏替換。可以用作同時聲明指標型的多個對象。比如:

char* pa, pb; // 這多數不符合我們的意圖,它只聲明了一個指向字元變數的指標,和一個字元變數;
以下則可行:
typedef char* PCHAR;
PCHAR pa, pb;


這種用法很有用,特別是char* pa, pb的定義,初學者往往認為是定義了兩個字元型指標,其實不是,而用typedef char* PCHAR就不會出現這樣的問題,減少了錯誤的發生。

用途二:

用在舊的C代碼中,協助struct。以前的代碼中,聲明struct新對象時,必須要帶上struct,即形式為: struct 結構名對象名,如:

struct tagPOINT1

{


int x;


int y;

};

struct tagPOINT1 p1;

而在C++中,則可以直接寫:結構名對象名,即:tagPOINT1 p1;

typedef struct tagPOINT
{
int x;
int y;
}POINT;

POINT p1; 

這樣就比原來的方式少寫了一個struct,比較省事,尤其在大量使用的時候,或許,在C++中,typedef的這種用途二不是很大,但是理解了它,對掌握以前的舊代碼還是有協助的,畢竟我們在項目中有可能會遇到較早些年代遺留下來的代碼。

用途三:

用typedef來定義與平台無關的類型。

比如定義一個叫 REAL 的浮點類型,在目標平台一上,讓它表示最高精度的類型為:
typedef long double REAL;
在不支援 long double 的平台二上,改為:
typedef double REAL;
在連 double 都不支援的平台三上,改為:
typedef float REAL;
也就是說,當跨平台時,只要改下 typedef 本身就行,不用對其他源碼做任何修改。


標準庫就廣泛使用了這個技巧,比如size_t。另外,因為typedef是定義了一種類型的新別名,不是簡單的字串替換,所以它比宏來得穩健。

這個優點在我們寫代碼的過程中可以減少不少代碼量哦!

用途四:

為複雜的聲明定義一個新的簡單的別名。方法是:在原來的聲明裡逐步用別名替換一部分複雜聲明,如此迴圈,把帶變數名的部分留到最後替換,得到的就是原聲明的最簡化版。舉例:

原聲明:void (*b[10]) (void (*)());

變數名為b,先替換右邊部分括弧裡的,pFunParam為別名一:

typedef void (*pFunParam)();

再替換左邊的變數b,pFunx為別名二:

typedef void (*pFunx)(pFunParam);

原聲明的最簡化版:

pFunx b[10];

原聲明:doube(*)() (*e)[9];

變數名為e,先替換左邊部分,pFuny為別名一:

typedef double(*pFuny)();

再替換右邊的變數e,pFunParamy為別名二

typedef pFuny (*pFunParamy)[9];

原聲明的最簡化版:

pFunParamy e;

理解複雜聲明可用的“右左法則”:從變數名看起,先往右,再往左,碰到一個圓括弧就調轉閱讀的方向;括弧內分析完就跳出括弧,還是按先右後左的順序,如此迴圈,直到整個聲明分析完。舉例:

int (*func)(int *p);

首先找到變數名func,外面有一對圓括弧,而且左邊是一個*號,這說明func是一個指標;然後跳出這個圓括弧,先看右邊,又遇到圓括弧,這說明(*func)是一個函數,所以func是一個指向這類函數的指標,即函數指標,這類函數具有int*類型的形參,傳回值類型是int。

int (*func[5])(int *);

func右邊是一個[ ]運算子,說明func是具有5個元素的數組;func的左邊有一個*,說明func的元素是指標(注意這裡的*不是修飾func,而是修飾func[5]的,原因是[]運算子優先順序比*高,func先跟[]結合)。跳出這個括弧,看右邊,又遇到圓括弧,說明func數組的元素是函數類型的指標,它指向的函數具有int*類型的形參,傳回值類型為int。

這種用法是比較複雜的,出現的頻率也不少,往往在看到這樣的用法卻不能理解,相信以上的解釋能有所協助。

下面還是舉個例子吧,將來如果真的用到就算賺了O(∩_∩)O~

 

#include<stdio.h>    typedef int (*FP_CALC)(int, int);  int add(int a, int b)  {       return a + b;  }  int sub(int a, int b)  {       return a - b;  }  int mul(int a, int b)  {       return a * b;  }  int div(int a, int b)  {       return b? a/b : -1;  }  FP_CALC calc_func(char op)  {       switch (op)       {       case '+': return add;//返回函數的地址       case '-': return sub;       case '*': return mul;       case '/': return div;       default:           return NULL;       }       return NULL;  }  int (*s_calc_func(char op)) (int, int)  {       return calc_func(op);  }   int calc(int a, int b, char op)  {  FP_CALC fp = calc_func(op); //根據預算符得到各種運算的函數的地址//同樣你也可以使用下面這種方法  //int (*s_fp)(int, int) = s_calc_func(op);//用於測試  //ASSERT(fp == s_fp);   // 可以斷言這倆是相等的  if (fp) return fp(a, b);  else return -1;  }    void main()  {     int a = 100, b = 20;  printf("calc(%d, %d, %c) = %d\n", a, b, '+', calc(a, b, '+'));  printf("calc(%d, %d, %c) = %d\n", a, b, '-', calc(a, b, '-'));  printf("calc(%d, %d, %c) = %d\n", a, b, '*', calc(a, b, '*'));  printf("calc(%d, %d, %c) = %d\n", a, b, '/', calc(a, b, '/'));  }  

結果

 

 

calc(100, 20, +) = 120calc(100, 20, -) = 80calc(100, 20, *) = 2000calc(100, 20, /) = 5

想要具體瞭解的可以看看這段代碼,相對理解起來簡單很多

 

待續。。。。。。

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.