C语言再学习 -- 关键字typedef
參看:C語言再學習 -- 結構和其他數據形式
參看:C語言再學習 -- 關鍵字struct(轉)
參看:常見typedef 用法
參看:關于typedef的用法總結
一、typedef 介紹
typedef為C語言的關鍵字,作用是為一種數據類型定義一個新名字。比如人們常常使用 typedef 來編寫更美觀和可讀的代碼。所謂美觀,意指 tepedef 能隱藏笨拙的語法構造以及平臺相關的數據類型,從而增強可移植性以及未來的可維護性。
這里的數據類型包括內部數據類型(int,char等)和自定義的數據類型(struct等)。 在編程中使用typedef目的一般有兩個,一個是給變量一個易記且意義明確的新名字,另一個是簡化一些比較復雜的類型聲明。
typedef 使用方法如下:
typedef existing_type new_type_name; 注意:typedef 并不創建新的類型。它僅僅為現有類型添加一個同義字。
typedef的簡單應用:
typedef unsigned char BYTE; BYTE b1, b2;
在這個類型定義之后,標識符 BYTE 可作為類型 unsigned char 的縮寫。該定義的作用域取決于 typedef 語句所在的位置。如果定義是在一個函數內部,它的作用域是局部的,限定在那個函數里。如果定義是在函數外部,它將具有全局作用域。
通常,這些定義使用大寫字母,以提醒用戶這個類型名稱實際上是一個符號縮寫。不過,您也可以使用小寫字母。
二、typedef 用法總結
1、typedef 與 define 區別
首先你要了解 typedef 和 define 的區別,宏定義只是簡單的字符串代換,是在預處理完成的,而typedef是在編譯時處理的,它不是作簡單的代換,而是對類型說明符重新命名。被命名的標識符具有類型定義說明的功能。
請看下面的例子:
#define P1 int *
typedef (int *) P2
從形式上看這兩者相似,但在實際使用中卻不相同。
下面用P1、P2說明變量時就可以看出它們的區別:
P1 a, b; ?在宏代換后變成: int *a, b; ?表示 a 是指向整型的指針變量,而 b 是整型變量。
P2 a, b; ?表示a,b都是指向整型的指針變量。因為PIN2是一個類型說明符。
由這個例子可見,宏定義雖然也可表示數據類型, 但畢竟是作字符代換。在使用時要分外小心,以避出錯。
總結,typedef和#define的不同之處:
1、與#define不同,typedef 給出的符號名稱僅限于對類型,而不是對值。
2、typedef 的解釋由編譯器,而不是是處理器執行。
3、雖然它的范圍有限,但在其受限范圍內,typedef 比 #define 更靈活。
2、常規變量類型定義
typedef 聲明可用來表示一個變量的含義。
例如:typedef unsigned char uchar
描述:uchar等價于unsigned char類型定義
? ? ? ? ? ?uchar c聲明等于unsigned char c聲明
3、數組類型定義
例如: typedef int array[2];
描述: array等價于 int [2]定義;
? ? ? ? ? ? array a聲明等價于int a[2]聲明
擴展: typedef int array[M][N];
描述: array等價于 int [M][N]定義;
? ? ? ? ? ? array a聲明等價于int a[M][N]聲明
4、指針類型定義
例如: typedef int *pointer;
描述: pointer等價于 int *定義;
? ? ? ? ? ? pointer p聲明等價于int *p聲明
例如: typedef int *pointer[M];
描述: pointer等價于 int *[M]定義;
? ? ? ? ? ? pointer p聲明等價于int *p[M]聲明
5、函數地址說明
描述: C把函數名字當做函數的首地址來對待,我們可以使用最簡單的方法得到函數地址
例如: 函數:int func(void);
? ? ? ? ? ? unsigned long funcAddr=(unsigned long)func;
? ? ? ? ? ? funcAddr的值是func函數的首地址
6、函數聲明
例如: typedef int func(void); ?
? ? ? ? ? ? func等價于 int (void)類型函數
描述1: func f聲明等價于 int f(void)聲明,用于文件的函數聲明
描述2: func *pf聲明等價于 int (*pf)(void)聲明,用于函數指針的聲明,見下一條
7、函數指針
例如: typedef int (*func)(void)
描述: func等價于int (*)(void)類型
? ? ? ? ? ? func pf等價于int (*pf)(void)聲明,pf是一個函數指針變量
8、識別typedef的方法:
a).第一步。使用已知的類型定義替代 typdef 后面的名稱,直到只剩下一個名字不識別為正確
? ? 如typedef u32 ? (*func)(u8);
? ? 從上面的定義中找到 typedef __u32 ?u32; typedef __u8 u8
? ? 繼續找到 typedef unsigned int __u32; typedef unsigned char __u8;
? ? 替代位置名稱 typedef unsigned int ?(*func)(void);
? ? 現在只有func屬于未知
b).第二步.未知名字為定義類型,類型為取出名稱和 typedef 的所有部分,如上為
? ? func等價于unsigned unsigned ?int ?(*)(unsigned ?char);
c).第三部.定義一個變量時,變量類型等價于把變量替代未知名字的位置所得到的類型
? ? func f等價于unsigned unsigned int ?(*f)(unsigned char)
9、結構體定義
結構體的一般定義形式為:
標簽(tag)字段允許為成員列表提供一個名字,這樣它就可以在后續的聲明中使用。標簽允許多個聲明使用同一個成員列表,并且創建同一種類型的結構。
[cpp]?view plaincopy10、結構體指針
struct Node {int data;struct Node *nextptr; };
使用 typede 上面的代碼可以改寫為如下:
typedef struct Node pNode; struct Node {int data;pNode *nextptr; };
或者
typedef struct Node{int data;struct Node *nextptr; }pNode;
三、typedef 用途
用途一:與#define的區別
typedef 行為有點像 #define 宏,用其實際類型替代同義字。不同點是 typedef 在編譯時被解釋,
因此讓編譯器來應付超越預處理器能力的文本替換。
?用途二:減少錯誤
定義一種類型的別名,而不只是簡單的宏替換??梢杂米魍瑫r聲明指針型的多個對象。比如:
[cpp]?view plaincopy print?
以下則可行:
[cpp]?view plaincopy print?
這種用法很有用,特別是char* pa, pb的定義,初學者往往認為是定義了兩個字符型指針,其實不是,而用typedef char* PCHAR就不會出現這樣的問題,減少了錯誤的發生。
用途三: ? ?直觀簡潔
用在舊的C代碼中,幫助struct。以前的代碼中,聲明struct新對象時,必須要帶上struct,即形式為: struct 結構名對象名,如:
[cpp]?view plaincopy print?
而在C++中,則可以直接寫:結構名對象名,即:tagPOINT1 p1;
[cpp]?view plaincopy print?
POINT p1; // 這樣就比原來的方式少寫了一個struct,比較省事,尤其在大量使用的時候,或許,在C++中,typedef的這種用途二不是很大,但是理解了它,對掌握以前的舊代碼還是有幫助的,畢竟我們在項目中有可能會遇到較早些年代遺留下來的代碼。
用途四:平臺無關性
用typedef來定義與平臺無關的類型。
typedef 有另外一個重要的用途,那就是定義機器無關的類型,例如,你可以定義一個叫 REAL 的浮點類型,在目標機器上它可以獲得最高的精度:? [cpp]?view plaincopy print?
也就是說,當跨平臺時,只要改下 typedef 本身就行,不用對其他源碼做任何修改。
標準庫就廣泛使用了這個技巧,比如size_t。另外,因為typedef是定義了一種類型的新別名,不是簡單的字符串替換,所以它比宏來得穩健。
用途五:掩飾復合類型
typedef 還可以掩飾復合類型,如指針和數組。?
例如,你不用像下面這樣重復定義有 81 個字符元素的數組:? [cpp]?view plaincopy print?
用途六:代碼簡化
代碼簡化。為復雜的聲明定義一個新的簡單的別名。方法是:在原來的聲明里逐步用別名替換一部分復雜聲明,如此循環,把帶變量名的部分留到最后替換,得到的就是原聲明的最簡化版。舉例:?
?原聲明:
[cpp]?view plaincopy print?
變量名為b,先替換右邊部分括號里的,pFunParam為別名
[cpp]?view plaincopy print?
再替換左邊的變量b,pFunx為別名二:
[cpp]?view plaincopy print?
原聲明的最簡化版:
[cpp]?view plaincopy print?
原聲明:
[cpp]?view plaincopy print?
變量名為e,先替換左邊部分,pFuny為別名一:
[cpp]?view plaincopy print?
再替換右邊的變量e,pFunParamy為別名二
[cpp]?view plaincopy print?
原聲明的最簡化版:
[cpp]?view plaincopy print?
理解復雜聲明可用的“右左法則”:從變量名看起,先往右,再往左,碰到一個圓括號就調轉閱讀的方向;括號內分析完就跳出括號,還是按先右后左的順序,如此循環,直到整個聲明分析完。舉例:
[cpp]?view plaincopy print?
首先找到變量名func,外面有一對圓括號,而且左邊是一個*號,這說明func是一個指針;然后跳出這個圓括號,先看右邊,又遇到圓括號,這說明(*func)是一個函數,所以func是一個指向這類函數的指針,即函數指針,這類函數具有int*類型的形參,返回值類型是int。
[cpp]?view plaincopy print?
func右邊是一個[]運算符,說明func是具有5個元素的數組;func的左邊有一個*,說明func的元素是指針(注意這里的*不是修飾func,而是修飾func[5]的,原因是[]運算符優先級比*高,func先跟[]結合)。跳出這個括號,看右邊,又遇到圓括號,說明func數組的元素是函數類型的指針,它指向的函數具有int*類型的形參,返回值類型為int。
用途七:typedef 和存儲類關鍵字(storage class specifier)?
這種說法是不是有點令人驚訝,typedef 就像 auto,extern,mutable,static,和 register 一樣,是一個存儲類關鍵字。這并不是說 typedef 會真正影響對象的存儲特性;它只是說在語句構成上,typedef 聲明看起來象 static,extern 等類型的變量聲明。下面將帶到第二個陷阱:?
[cpp]?view plaincopy print?編譯通不過。問題出在你不能在聲明中有多個存儲類關鍵字。因為符號 typedef 已經占據了存儲類關鍵字的位置,在 typedef 聲明中不能用 register(或任何其它存儲類關鍵字)。
與50位技術專家面對面20年技術見證,附贈技術全景圖
總結
以上是生活随笔為你收集整理的C语言再学习 -- 关键字typedef的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: C语言再学习 -- 关键字struct(
- 下一篇: 3、WordCount源码分析