typedef在C中是定義數(shù)據(jù)類型別名的,例如typedef int a;則a是與int 具有相同功能的別名,,相當(dāng)于我們說的給一個人起綽號,,其實(shí)他們是同一個人,這里也一樣,,這樣一個定義之后,,a就與int是一回事了
typedef char * a,* b;這里也一個意思啊,,這句話就是定義了char*型的別名a與b,那么a與b就有了與char*相同的功能了,,那么我們?nèi)绻x a num;則num就被定義為char*型的指針了 關(guān)于typedef的用法 int* (*a[5])(int, char*); //#1 void (*b[10]) (void (*)()); //#2 double(*)() (*pa)[9]; //#3 1.C語言中函數(shù)聲明和數(shù)組聲明。函數(shù)聲明一般是這樣: int fun(int, double); 對應(yīng)函數(shù)指針(pointer to function)的聲明是這樣: int (*pf)(int, double),; 可以這樣使用: pf = &fun; //賦值(assignment)操作 (*pf)(5, 8.9);//函數(shù)調(diào)用操作 也請注意,,C語言本身提供了一種簡寫方式如下: pf = fun; // 賦值(assignment)操作 pf(5, 8.9); // 函數(shù)調(diào)用操作 不過我本人不是很喜歡這種簡寫,它對初學(xué)者帶來了比較多的迷惑,。 數(shù)組聲明一般是這樣: int a[5],; 對于數(shù)組指針(pointer to array)的聲明是這樣: int (*pa)[5]; 可以這樣使用: pa = &a; // 賦值(assignment)操作 int i = (*pa)[2]; // 將a[2]賦值給i,; 2.有了上面的基礎(chǔ),,我們就可以對付開頭的三只紙老虎了!:) 這個時候你需要復(fù)習(xí)一下各種運(yùn)算符的優(yōu)先順序和結(jié)合順序了,順便找本書看看就夠了,。 #1:int* (*a[5])(int, char*); 首先看到標(biāo)識符名a,,“[]”優(yōu)先級大于“*”,a與“[5]”先結(jié)合,。所以a是一個數(shù)組,,這個數(shù)組有5個元素,每一個元素都是一個指針,, 指針指向“(int, char*)”,,對,指向一個函數(shù),,函數(shù)參數(shù)是“int, char*”,,返回值是“int*”,。完畢,,我們干掉了第一個紙老虎。:) #2:void (*b[10]) (void (*)()); b是一個數(shù)組,,這個數(shù)組有10個元素,,每一個元素都是一個指針,指針指向一個函數(shù),,函數(shù)參數(shù)是“void (*)()”【注1】,,返回值是“void”。完畢,! 注1:這個參數(shù)又是一個指針,,指向一個函數(shù),函數(shù)參數(shù)為空,,返回值是“void”,。 #3:double(*)()(*pa)[9]; pa是一個指針,指針指向一個數(shù)組,,這個數(shù)組有9個元素,,每一個元素都是“double(*)()”【也即一個指針,指向一個函數(shù),,函數(shù)參數(shù)為空,,返回值是“double”】。(注意typedef int* p[9]與typedef int(*p)[9]的區(qū)別,,前者定義一個數(shù)組,,此數(shù)組包含9個int*類型成員,而后者定義一個指向數(shù)組的指針,被指向的數(shù)組包含9個int類型成員),。 現(xiàn)在是不是覺得要認(rèn)識它們是易如反掌,,工欲善其事,必先利其器,!我們對這種表達(dá)方式熟悉之后,,就可以用“typedef”來簡化這種類型聲明。 #1:int* (*a[5])(int, char*); typedef int* (*PF)(int, char*);//PF是一個類型別名【注2】,。 PF a[5];//跟int* (*a[5])(int, char*);的效果一樣,! 注2:很多初學(xué)者只知道typedef char* pchar;但是對于typedef的其它用法不太了解,。Stephen Blaha對typedef用法做過一個總結(jié):“建立一個類型別名的方法很簡單,,在傳統(tǒng)的變量聲明表達(dá)式里用類型名替代變量名,然后把關(guān)鍵字typedef加在該語句的開頭”,。 #2:void (*b[10])(void (*)()); typedef void (*pfv)(); typedef void (*pf_taking_pfv)(pfv); pf_taking_pfv b[10]; //跟void (*b[10]) (void (*)());的效果一樣,! #3. double(*)()(*pa)[9]; typedef double(*PF)(); typedef PF (*PA)[9]; PA pa; //跟doube(*)()(*pa)[9];的效果一樣! 3.const和volatile在類型聲明中的位置,。 在這里我只說const,,volatile是一樣的!【注3】 注3:顧名思義,volatile修飾的量就是很容易變化,,不穩(wěn)定的量,,它可能被其它線程,操作系統(tǒng),,硬件等等在未知的時間改變,, 所以它被存儲在內(nèi)存中,每次取用它的時候都只能在內(nèi)存中去讀取,,它不能被編譯器優(yōu)化放在內(nèi)部寄存器中,。 類型聲明中const用來修飾一個常量,我們一般這樣使用:const在前面: const int,; //int是const const char*;//char是const char* const;//*(指針)是const const char* const;//char和*都是const 對初學(xué)者,,const char*和 char* const是容易混淆的。這需要時間的歷練讓你習(xí)慣它,。 上面的聲明有一個對等的寫法:const在后面: int const,; //int是const char const*;//char是const char* const;//*(指針)是const char const* const;//char和*都是const 第一次你可能不會習(xí)慣,但新事物如果是好的,,我們?yōu)槭裁匆芙^它呢,?:)const在后面有兩個好處: A.const所修飾的類型正好是在它前面的那一個。如果這個好處還不能讓你動心的話,,那請看下一個,! B.我們很多時候會用到typedef的類型別名定義,。比如typedef char* pchar,如果用const來修飾的話,, 當(dāng)const在前面的時候,,就是const pchar,你會以為它就是const char* ,,但是你錯了,,它的真實(shí)含義是char* const。 是不是讓你大吃一驚,!但如果你采用const在后面的寫法,,意義就怎么也不會變,不信你試試,! 不過,,在真實(shí)項(xiàng)目中的命名一致性更重要。你應(yīng)該在兩種情況下都能適應(yīng),,并能自如的轉(zhuǎn)換,,公司習(xí)慣, 商業(yè)利潤不論在什么時候都應(yīng)該優(yōu)先考慮,!不過在開始一個新項(xiàng)目的時候,,你可以考慮優(yōu)先使用const在后面的習(xí)慣用法。 二.Typedef聲明有助于創(chuàng)建平臺無關(guān)類型,,甚至能隱藏復(fù)雜和難以理解的語法,。 不管怎樣,使用 typedef 能為代碼帶來意想不到的好處,,通過本文你可以學(xué)習(xí)用typedef避免缺欠,從而使代碼更健壯,。 typedef聲明,,簡稱typedef,為現(xiàn)有類型創(chuàng)建一個新的名字,。比如人們常常使用 typedef 來編寫更美觀和可讀的代碼,。 所謂美觀,意指typedef 能隱藏笨拙的語法構(gòu)造以及平臺相關(guān)的數(shù)據(jù)類型,,從而增強(qiáng)可移植性和以及未來的可維護(hù)性,。 本文下面將竭盡全力來揭示 typedef 強(qiáng)大功能以及如何避免一些常見的陷阱,如何創(chuàng)建平臺無關(guān)的數(shù)據(jù)類型,隱藏笨拙且難以理解的語法. typedef使用最多的地方是創(chuàng)建易于記憶的類型名,,用它來歸檔程序員的意圖,。類型出現(xiàn)在所聲明的變量名字中,位于typedef關(guān)鍵字右邊,。 例如:typedef int size; 此聲明定義了一個 int 的同義字,,名字為 size。注意typedef并不創(chuàng)建新的類型。它僅僅為現(xiàn)有類型添加一個同義字,。 你可以在任何需要 int 的上下文中使用 size: void measure(size * psz); size array[4]; size len = file.getlength(); typedef 還可以掩飾復(fù)合類型,,如指針和數(shù)組。例如,,你不用象下面這樣重復(fù)定義有81個字符元素的數(shù)組: char line[81]; char text[81]; 定義一個typedef,,每當(dāng)要用到相同類型和大小的數(shù)組時,,可以這樣: typedef char Line[81]; Line text, secondline; getline(text); 同樣,,可以象下面這樣隱藏指針語法: typedef char * pstr; int mystrcmp(pstr, pstr); 這里將帶我們到達(dá)第一個 typedef 陷阱。標(biāo)準(zhǔn)函數(shù) strcmp()有兩個const char *類型的參數(shù),。因此,,它可能會誤導(dǎo)人們象下面這樣聲明: int mystrcmp(const pstr, const pstr); 這是錯誤的,事實(shí)上,,const pstr被編譯器解釋為char * const(一個指向 char 的常量指針),,而不是const char *(指向常量 char 的指針)。 這個問題很容易解決: typedef const char * cpstr; int mystrcmp(cpstr, cpstr); 上面討論的 typedef 行為有點(diǎn)像 #define 宏,,用其實(shí)際類型替代同義字,。不同點(diǎn)是typedef在編譯時被解釋 ,因此讓編譯器來應(yīng)付超越預(yù)處理器能力的文本替換,。例如: typedef int (*PF) (const char *, const char *); 這個聲明引入了 PF 類型作為函數(shù)指針的同義字,,該函數(shù)有兩個 const char * 類型的參數(shù)以及一個 int 類型的返回值。如果要使用下列形式的函數(shù)聲明,,那么上述這個 typedef 是不可或缺的: PF Register(PF pf); Register()的參數(shù)是一個PF類型的回調(diào)函數(shù),,返回某個函數(shù)的地址,其署名與先前注冊的名字相同,。做一次深呼吸,。下面我展示一下如果不用 typedef,我們是如何實(shí)現(xiàn)這個聲明的: int (*Register (int (*pf)(const char *, const char *))) (const char *, const char *); 很少有程序員理解它是什么意思,,更不用說這種費(fèi)解的代碼所帶來的出錯風(fēng)險(xiǎn)了,。顯然,這里使用 typedef 不是一種特權(quán),, 而是一種必需,。typedef 就像 auto,extern,,mutable,,static,和 register 一樣,,是一個存儲類關(guān)鍵字,。 這并不是說typedef會真正影響對象的存儲特性,;它只是說在語句構(gòu)成上,typedef 聲明看起來象 static,,extern 等類型的變量聲明,。 下面將帶到第二個陷阱: typedef register int FAST_COUNTER; // 錯誤編譯通不過 問題出在你不能在聲明中有多個存儲類關(guān)鍵字。因?yàn)榉?typedef 已經(jīng)占據(jù)了存儲類關(guān)鍵字的位置,, 在 typedef 聲明中不能用 register(或任何其它存儲類關(guān)鍵字),。typedef 有另外一個重要的用途,那就是定義機(jī)器無關(guān)的類型,, 例如,,你可以定義一個叫 REAL 的浮點(diǎn)類型,在目標(biāo)機(jī)器上它可以獲得最高的精度: typedef long double REAL; 在不支持 long double 的機(jī)器上,,該 typedef 看起來會是下面這樣: typedef double REAL; 并且,,在連 double 都不支持的機(jī)器上,該 typedef 看起來會是這樣: typedef float REAL; 你不用對源代碼做任何修改,,便可以在每一種平臺上編譯這個使用 REAL 類型的應(yīng)用程序,。唯一要改的是 typedef 本身。 在大多數(shù)情況下,,甚至這個微小的變動完全都可以通過奇妙的條件編譯來自動實(shí)現(xiàn),。不是嗎? 標(biāo)準(zhǔn)庫廣泛地使用 typedef 來創(chuàng)建這樣的平臺無關(guān)類型:size_t,ptrdiff 和 fpos_t 就是其中的例子,。 此外,,象 std::string 和 std::ofstream 這樣的 typedef 還隱藏了長長的,難以理解的模板特化語法,, 例如:basic_string,,allocator> 和 basic_ofstream>。 typedef在C中是定義數(shù)據(jù)類型別名的,,例如typedef int a;則a是與int 具有相同功能的別名,,相當(dāng)于我們說的給一個人起綽號,其實(shí)他們是同一個人,,這里也一樣,這樣一個定義之后,,a就與int是一回事了
typedef char * a,* b,;這里也一個意思啊,這句話就是定義了char*型的別名a與b,那么a與b就有了與char*相同的功能了,,那么我們?nèi)绻x a num;則num就被定義為char*型的指針了 typedef在C中是定義數(shù)據(jù)類型別名的,,例如typedef int a;則a是與int 具有相同功能的別名,相當(dāng)于我們說的給一個人起綽號,,其實(shí)他們是同一個人,,這里也一樣,,這樣一個定義之后,a就與int是一回事了 typedef char * a,* b,;這里也一個意思啊,,這句話就是定義了char*型的別名a與b,那么a與b就有了與char*相同的功能了,那么我們?nèi)绻x a num;則num就被定義為char*型的指針了 typedef可以增強(qiáng)程序的可讀性,,以及標(biāo)識符的靈活性,,但它也有“非直觀性”等缺點(diǎn)。 typedef 還可以掩飾符合類型,,如指針和數(shù)組,。例如,你不用象下面這樣重復(fù)定義有 81 個字符元素的數(shù)組: char line[81]; char text[81]; 定義一個 typedef,,每當(dāng)要用到相同類型和大小的數(shù)組時,,可以這樣: typedef char Line[81]; Line text, secondline; getline(text); 同樣,可以象下面這樣隱藏指針語法: typedef char * pstr; int mystrcmp(pstr, pstr); 這里將帶我們到達(dá)第一個 typedef 陷阱,。標(biāo)準(zhǔn)函數(shù) strcmp()有兩個‘const char *’類型的參數(shù),。因此,它可能會誤導(dǎo)人們象下面這樣聲明 mystrcmp(): int mystrcmp(const pstr, const pstr); 這是錯誤的,,按照順序,,‘const pstr’被解釋為‘char * const’(一個指向 char 的常量指針),而不是‘const char *’(指向常量 char 的指針),。這個問題很容易解決: typedef const char * cpstr; int mystrcmp(cpstr, cpstr); // 現(xiàn)在是正確的 記?。?/strong>不管什么時候,只要為指針聲明 typedef,,那么都要在最終的 typedef 名稱中加一個 const,,以使得該指針本身是常量,而不是對象,。 typedef int (*PF) (const char *, const char *); 這個聲明引入了 PF 類型作為函數(shù)指針的同義字,該函數(shù)有兩個 const char * 類型的參數(shù)以及一個 int 類型的返回值,。如果要使用下列形式的函數(shù)聲明,,那么上述這個 typedef 是不可或缺的: PF Register(PF pf); Register() 的參數(shù)是一個 PF 類型的回調(diào)函數(shù),返回某個函數(shù)的地址,,其署名與先前注冊的名字相同,。做一次深呼吸。下面我展示一下如果不用 typedef,,我們是如何實(shí)現(xiàn)這個聲明的: int (*Register (int (*pf)(const char *, const char *))) (const char *, const char *); 很少有程序員理解它是什么意思,,更不用說這種費(fèi)解的代碼所帶來的出錯風(fēng)險(xiǎn)了,。顯然,這里使用 typedef 不是一種特權(quán),,而是一種必需,。持懷疑態(tài)度的人可能會問:“OK,有人還會寫這樣的代碼嗎,?”,,快速瀏覽一下揭示 signal()函數(shù)的頭文件 <csinal>,一個有同樣接口的函數(shù),。 typedef register int FAST_COUNTER; // 錯誤 編譯通不過,。問題出在你不能在聲明中有多個存儲類關(guān)鍵字,。因?yàn)榉?typedef 已經(jīng)占據(jù)了存儲類關(guān)鍵字的位置,在 typedef 聲明中不能用 register(或任何其它存儲類關(guān)鍵字),。 typedef long double REAL; 在不支持 long double 的機(jī)器上,該 typedef 看起來會是下面這樣: typedef double REAL; 并且,,在連 double 都不支持的機(jī)器上,,該 typedef 看起來會是這樣: 、 typedef float REAL; |
|