關于馬甲的笑話。有這樣一個笑話:一個獵人在河邊抓捕一條蛇,蛇逃進了水里。過一會,一個烏龜爬到岸邊。獵人一把抓住這個烏龜,大聲的說道:小樣,別你為你穿了個馬甲我就不認識你了!
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”。只不過這兩個名字同時取而已,好比你給你家小狗取了個別名叫“大黃”,同時你妹妹給小狗帶了小帽子,然后給它取了個別名叫“小可愛”。^_^。
好,下面再把typedef 與const 放在一起看看:
C),const Stu_pst stu3;
D),Stu_pst const stu4;
大多數初學者認為C)里const 修飾的是stu3 指向的對象;D)里const 修飾的是stu4這個指針。很遺憾,C)里const 修飾的并不是stu3 指向的對象。那const 這時候到底修飾的是什么呢?我們在講解const int i 的時候說過const 放在類型名“int”前后都行;而const int?*p 與int * const p 則完全不一樣。 也就是說,我們看const 修飾誰都時候完全可以將數據類型名視而不見,當它不存在。反過來再看“const Stu_pst stu3”,Stu_pst 是“struct student?{ /*code*/} *”的別名, “struct student {/*code*/} *”是一個整體。 對于編譯器來說,只認為Stu_pst 是一個類型名,所以在解析的時候很自然的把“Stu_pst”這個數據類型名忽略掉。
現在知道const 到底修飾的是什么了吧?^_^。
E) #define INT32 int
? ? ? ?unsigned INT32 i = 10;
F)typedef int int32;
? ? ? unsigned int32 j = 10;
其中F)編譯出錯,為什么呢?E)不會出錯,這很好理解, 因為在預編譯的時候INT32被替換為int,而unsigned int i = 10;語句是正確的。但是,很可惜,用typedef 取的別名不支持這種類型擴展。另外,想想typedef static int int32 行不行?為什么?
下面再看一個與#define 宏有關的例子:
G) ?#define PCHAR char*
? ? ? PCHAR p3,p4;
H)typedef char* pchar;
? ? ? ?pchar p1,p2;
兩組代碼編譯都沒有問題, 但是,這里的p4 卻不是指針,僅僅是一個char 類型的字符。這種錯誤很容易被忽略,所以用#define 的時候要慎之又慎。關于#define 當然還有很多話題需要討論,請看預處理那一章。當然關于typedef 的討論也還沒有結束,在指針與數組那一章,我們還要繼續討論。
1)#define a int[10]
A),a[10] a[10];
B),a[10] a;
C),int a[10];
D),int a;
E),a b[10];
F),a b;
G),a* b[10];
H),a* b;
2) typedef int a[10];
A),a[10] a[10];
B),a[10] a;
C),int a[10];
D),int a;
E),a b[10];
F),a b;
G),a* b[10];
H),a* b;
3) #define a int*[10]
A),a[10] a[10];
B),a[10] a;
C),int a[10];
D),int a;
E),a b[10];
F),a b;
G),a* b[10];
H),a* b;
4) ? typedef int * a[10];
A),a[10] a[10];
B),a[10] a;
C),int a[10];
D),int a;
E),a b[10];
F),a b;
G),a* b[10];
H),a* b;
5) #define *a int[10]
A),a[10] a[10];
B),a[10] a;
C),int a[10];
D),int a;
E),a b[10];
F),a b;
G),a* b[10];
H),a* b;
6) ? typedef int (* a)[10];
A),a[10] a[10];
B),a[10] a;
C),int a[10];
D),int a;
E),a b[10];
F),a b;
G),a* b[10];
H),a* b;
7) #define *a * int[10]
A),a[10] a[10];
B),a[10] a;
C),int a[10];
D),int a;
E),a b[10];
F),a b;
G),a* b[10];
H),a* b;
8) ?typedef int * (* a)[10];
A),a[10] a[10];
B),a[10] a;
C),int a[10];
D),int a;
E),a b[10];
F),a b;
G),a* b[10];
H),a* b;
請判斷這里面哪些定義正確,哪些定義不正確。另外,int[10]和a[10]到底該怎么用?
typedef 關鍵字是個偉大的縫紉師,擅長做馬甲,任何東西穿上這個馬甲就立馬變樣。它可以把狼變成一頭羊,也能把羊變成一頭狼。甚至還可以把長著翅膀的鳥人變成天使,同樣也能把美麗的天使變成鳥人。所以,你千萬不要得罪它,一定要掌握它的脾氣,不然哪天我把你當鳥人,你可別怪我。^_^。
一、歷史的誤會——也許應該是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”。只不過這兩個名字同時取而已,好比你給你家小狗取了個別名叫“大黃”,同時你妹妹給小狗帶了小帽子,然后給它取了個別名叫“小可愛”。^_^。
好,下面再把typedef 與const 放在一起看看:
C),const Stu_pst stu3;
D),Stu_pst const stu4;
大多數初學者認為C)里const 修飾的是stu3 指向的對象;D)里const 修飾的是stu4這個指針。很遺憾,C)里const 修飾的并不是stu3 指向的對象。那const 這時候到底修飾的是什么呢?我們在講解const int i 的時候說過const 放在類型名“int”前后都行;而const int?*p 與int * const p 則完全不一樣。 也就是說,我們看const 修飾誰都時候完全可以將數據類型名視而不見,當它不存在。反過來再看“const Stu_pst stu3”,Stu_pst 是“struct student?{ /*code*/} *”的別名, “struct student {/*code*/} *”是一個整體。 對于編譯器來說,只認為Stu_pst 是一個類型名,所以在解析的時候很自然的把“Stu_pst”這個數據類型名忽略掉。
現在知道const 到底修飾的是什么了吧?^_^。
二、typedef 與#define 的區別
噢,上帝!這真要命!別急,要命的還在后面呢。看如下例子:E) #define INT32 int
? ? ? ?unsigned INT32 i = 10;
F)typedef int int32;
? ? ? unsigned int32 j = 10;
其中F)編譯出錯,為什么呢?E)不會出錯,這很好理解, 因為在預編譯的時候INT32被替換為int,而unsigned int i = 10;語句是正確的。但是,很可惜,用typedef 取的別名不支持這種類型擴展。另外,想想typedef static int int32 行不行?為什么?
下面再看一個與#define 宏有關的例子:
G) ?#define PCHAR char*
? ? ? PCHAR p3,p4;
H)typedef char* pchar;
? ? ? ?pchar p1,p2;
兩組代碼編譯都沒有問題, 但是,這里的p4 卻不是指針,僅僅是一個char 類型的字符。這種錯誤很容易被忽略,所以用#define 的時候要慎之又慎。關于#define 當然還有很多話題需要討論,請看預處理那一章。當然關于typedef 的討論也還沒有結束,在指針與數組那一章,我們還要繼續討論。
三、#define a int[10]與typedef int a[10];
留兩個問題:1)#define a int[10]
A),a[10] a[10];
B),a[10] a;
C),int a[10];
D),int a;
E),a b[10];
F),a b;
G),a* b[10];
H),a* b;
2) typedef int a[10];
A),a[10] a[10];
B),a[10] a;
C),int a[10];
D),int a;
E),a b[10];
F),a b;
G),a* b[10];
H),a* b;
3) #define a int*[10]
A),a[10] a[10];
B),a[10] a;
C),int a[10];
D),int a;
E),a b[10];
F),a b;
G),a* b[10];
H),a* b;
4) ? typedef int * a[10];
A),a[10] a[10];
B),a[10] a;
C),int a[10];
D),int a;
E),a b[10];
F),a b;
G),a* b[10];
H),a* b;
5) #define *a int[10]
A),a[10] a[10];
B),a[10] a;
C),int a[10];
D),int a;
E),a b[10];
F),a b;
G),a* b[10];
H),a* b;
6) ? typedef int (* a)[10];
A),a[10] a[10];
B),a[10] a;
C),int a[10];
D),int a;
E),a b[10];
F),a b;
G),a* b[10];
H),a* b;
7) #define *a * int[10]
A),a[10] a[10];
B),a[10] a;
C),int a[10];
D),int a;
E),a b[10];
F),a b;
G),a* b[10];
H),a* b;
8) ?typedef int * (* a)[10];
A),a[10] a[10];
B),a[10] a;
C),int a[10];
D),int a;
E),a b[10];
F),a b;
G),a* b[10];
H),a* b;
請判斷這里面哪些定義正確,哪些定義不正確。另外,int[10]和a[10]到底該怎么用?