typedef 深入剖析
typedef是一個我們常常會用到的關鍵字,而這個關鍵字有許多陷阱或者說許多不為我們深入理解的地方。很多書上都是很簡單地一筆代過,并沒有真正地讓我們理解這個關鍵字。本文對其進行詳細地說明。
綜合網絡上找到的資料對其進行分析,這其中會涉及到一些其他c方面的內容(比如指針,指向函數的指針,編譯時候數據類型未定義與完全定義知識等等),看到這些內容的時候大家可以忽略,這個重點是在typedef。
好了,不說那么多開始吧。
<h4>typedef的定義</h4>
typedef 是一個關鍵字,后面是數據類型和標識符。標識符或類型名并沒有引入新的類型,而只是現有數據類型的同義詞。
它用來對一個類型起一個新名字,也用來聲明自定義數據類型,其實給一個類型起新名字的作用也包含在聲明自定義數據類型這個功能中。
1.給一個類型起一個新名字
給一個類型其新名字,有時候可以幫助我們更好地記憶。
例子:
<pre lang="c" escaped="true">typedef int inter;</pre>
此聲明定義了一個 int 的同義字,名字為 inter。注意 在這里typedef 并不創建新的類型。它僅僅為現有類型添加一個同義字。你可以在任何需要 int 的上下文中使用 inter,即可以用inter來代替int進行整數變量的定義。
這個功能是最常用的,而且相對來說是比較簡單的。
2.定義新的類型
定義新的類型有多種形式,下面簡單的列一些。
<pre lang="c" escaped="true">typedef BaseType NewType [arrSize]</pre>
這種類型可以掩飾一些符合類型,其中BaseType是基本類型,NewType是我們所定義的新類型,這個新定義的NewType可以像其他的基本類型那樣使用。下面舉個例子:
<pre lang="c" escaped="true">typedef char Array[10]; </pre>
這里的char就是基本的類型,而Array是我們新定義的類型。這里Array是一個字符型的數組類型,這個數組類型的長度為10。下面我們就可以用Array來進行一些定義了。
<pre lang="c" escaped="true"> Array array1,array2;</pre>
這里我就定義了兩個Array型的數組,這兩個數組都是字符型的有10個元素的數組;如果我們沒有用typedef定義,那么我么就要進行下面這樣的定義:
<pre lang="c" escaped="true"> char array1[10];char array2[10]。</pre>
這種形式可以應用到指針等。
這里引入typedef一個陷阱:
<pre lang="c" escaped="true">
typedef char * pstr;
int mystrcmp(pstr, pstr);
</pre>
我們知道,標準函數 strcmp()有兩個"const char *"類型的參數。因此,它可能會誤導人們象下面這樣聲明 mystrcmp():
<pre lang="c" escaped="true"> int mystrcmp(const pstr, const pstr); </pre>
用GNU的gcc和g++編譯器,是會出現警告的,按照順序,"const pstr"被解釋為"char* const"(一個指向 char 的常量指針),兩者表達的并非同一意思。應該按以下方式定義:
<pre lang="c" escaped="true">
typedef const char* pstr;
</pre>
函數類型的形式
<pre lang="c" escaped="true">typedef int (*PF) (const char *, const char *)</pre>
這種類似的形式
這個聲明引入了 PF 類型作為函數指針的同義字,該函數有兩個 const char * 類型的參數以及一個 int 類型的返回值。這種定義的用途過會在下面以例子的形式給出。
typedef 就像 auto,extern,mutable,static,和 register 一樣,是一個存儲類關鍵字。這并不是說 typedef 會真正影響對象的存儲特性;它只是說在語句構成上,typedef 聲明看起來象 static,extern 等類型的變量聲明。這一點對于我們理解typedef定義新類型的功能很有用。
這里引入typedef另外一個陷阱:
<pre lang="c" escaped="true"> typedef register int FAST_COUNTER; </pre>
編譯通不過。問題出在你不能在聲明中有多個存儲類關鍵字。因為符號 typedef 已經占據了存儲類關鍵字的位置,在 typedef 聲明中不能用 register(或任何其它存儲類關鍵字)。
?
3.typedef與結構體結合使用
<pre lang="c" escaped="true">
struct var {
int data1;
int data2;
char data3;
};
</pre>
這里定義一個類型var,而要定義這種類型的變量,必須這樣寫:struct var a;若添加typedef struct var newtype;則定義變量只需這樣即可:newtype a;
typedef和結構體一般不這樣使用,而是按下面這樣子:
<pre lang="c" escaped="true">
typedef struct var {
int data1;
int data2;
char data3;
} newtype;
newtype a;
</pre>
在鏈表中更一般的形式:
<pre lang="c" escaped="true">
typedef struct tagNode
{
char *pItem;
struct tagNode *pNext; //這里不能寫為*pNode *pNext;
} *pNode;
</pre>
<pre lang="c" escaped="true">
或者 typedef struct tagNode *pNode;
struct tagNode
{
char *pItem;
pNode pNext;
};
</pre>
typedef 有另外一個重要的用途,那就是定義機器無關的類型,例如,你可以定義一個叫 REAL 的浮點類型,在目標機器上它可以獲得最高的精度:
<pre lang="c" escaped="true">typedef long double REAL; </pre>
在不支持 long double 的機器上,該 typedef 看起來會是下面這樣:
<pre lang="c" escaped="true">typedef double REAL; </pre>
并且,在連 double 都不支持的機器上,該 typedef 看起來會是這樣:
<pre lang="c" escaped="true"> typedef float REAL; </pre>
4.linux內核中typedef的例子:
<pre lang="c" escaped="true">typedef int (*PF) (const char *, const char *) </pre>
前面提到的這種類似的形式是可以簡化函數的,而且便于理解。舉linux內核中信號處理函數這個例子:
<pre lang="c" escaped="true"> void (*signal (int signr,void (*handler)(int))) (int) </pre>
其用typedef定義如下:
<pre lang="c" escaped="true">
typedef void sigfunc(int);
sigfunc *signal(int signr,sigfunc *handler);
</pre>
其中typedef定義了一個有一個整型參數無返回值的函數類型。void (*handler)(int)表示一個有一個整型參數無返回值的函數指針,這個指針名為handler,所以其可以用sigfunc進行說明,此時sigfunc就相當于前面的int signr中int的作用;同理這個函數也是這樣。
注:對復雜變量建立一個類型別名的方法很簡單,你只要在傳統的變量聲明表達式里用類型名替代變量名,然后把關鍵字typedef加在該語句的開頭就行了。
<pre lang="c" escaped="true">
int *(*a[5])(int, char*);
//pFun是我們建的一個類型別名
typedef int *(*pFun)(int, char*);
//使用定義的新類型來聲明對象,等價于int* (*a[5])(int, char*);
pFun a[5];
</pre>
轉載于:https://www.cnblogs.com/liweilijie/p/4984199.html
總結
以上是生活随笔為你收集整理的typedef 深入剖析的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: php支付接口要改动的参数,php支付接
- 下一篇: 地球化学图解系统GCDPlot 0.33