預(yù)計(jì)閱讀時(shí)間: 4 分鐘
Typedef 應(yīng)該算是很熟悉的關(guān)鍵字了,但是我也只是簡單使用罷了,為了比較系統(tǒng)的講述這一小節(jié),特地上網(wǎng)搜了一下。
好了,現(xiàn)在正式開始講解。
Typedef 關(guān)鍵字可以用于給數(shù)據(jù)類型定義一個別名,比如說你本名叫關(guān)谷神奇,我嫌棄這個名字太長了,所以給你取一個別名,叫關(guān)谷,以后我叫關(guān)谷的時(shí)候你就知道在叫你了。
當(dāng)你定義了一個結(jié)構(gòu)體時(shí),每次創(chuàng)建一個結(jié)構(gòu)體都要使用 struct+結(jié)構(gòu)體名 的方式,而用了 typedef 之后,只要一個結(jié)構(gòu)體別名就可以創(chuàng)建了。
并且有了別名,本名我都可以不要了(當(dāng)然你也可以加上)。
雖然說簡化寫法是一個不錯的功能,但卻不是一個很必要的功能。那么肯定有別的好處才是。
我們知道 C 語言定義數(shù)據(jù)類型的時(shí)候只定義了它們之間的關(guān)系,但卻沒有具體定義它們的大小。比如 short 的長度只規(guī)定了不大于 int,long 的長度不小于 int,int 是多大也沒確定,所以你會看到 51 單片機(jī)的 int 大小為兩個字節(jié),而在 stm32 中的長度為 4 字節(jié)。所以這個時(shí)候有必要使用一個別名來代替具體的數(shù)據(jù)類型,并且最好這個別名有一定的說明性,所以你會看到 stm32 庫函數(shù)有這么一堆申明:
這樣一旦后期換了平臺,我就知道怎么根據(jù)新平臺修改這個定義了,因?yàn)檫@個別名已經(jīng)有長度、符號信息了。
從 51 過來的讀者可能會說,干嘛要用 typedef,使用 #define (關(guān)于 #define 可以查看 #define 小節(jié))也能有相同的效果。確實(shí)是,但是 #define 嚴(yán)格來說它只是用來替換的,而 typedef 是專業(yè)的。所以使用 #define 可能一不小心就會給你挖坑了。
比如上面的,雖然本意是定義兩個指針的,但是 #define 比較笨,只會簡單替換,所以替換后成了這個樣子:
所以只有一個被定義成了指針,而如果使用 typedef 就沒有這個問題。
并且可以多次使用 typedef 定義一個別名,方便理解。
這個聲明還是比較難理解的,看起來像一個函數(shù),實(shí)際上,它是一個數(shù)組,這個數(shù)組存放了 3 個函數(shù)指針,而這個函數(shù)返回值為 long*,參數(shù)為 int*、char*,這是因?yàn)?fun 首先和 [] 結(jié)合,所以先是一個數(shù)組,然后才定義了數(shù)組存放的數(shù)據(jù)類型。
如果使用多次定義的話就容易理解一些了:
這樣一來就簡化了數(shù)據(jù)類型的定義和聲明了。所以在看別人的代碼的時(shí)候你會發(fā)現(xiàn)很多這樣的聲明,這是因?yàn)榇_實(shí)很方便啊。
雖說 typedef 在取別名上是專業(yè)的,但是如果你不熟悉而貿(mào)然使用的話也可能會為你挖坑的。下面介紹使用 typedef 時(shí)的一些坑:
1、 Const
在和 const 一起使用的時(shí)候,本想定義一個指向的字符為常量的變量指針,但 typedef 的特殊性,不是簡單的替換,所以最終的定義的是指向的字符為變量的常量指針。
解決的辦法就是在 typedef 中加 const 即可:
這樣就沒有問題了。
看到這里可能對以下寫法可能會模糊了:
怎么看哪個可以變,哪個不可以變呢?
就看 const 修飾哪一個了。如果說 const 離 char近,就是字符不變,如果 const 離指針名比較近,那就是指針不變,其他類似的,好好理解一下就差不多了。如果實(shí)在不理解也沒關(guān)系,忘記了再回來查一下就行,但是你得知道使用 typedef 有這么一個坑在就行了。
2、 存儲類
typedef 不影響對象的存儲特性,但是在語法上它卻是一個存儲類的關(guān)鍵字,就像 auto、extern、static、register 等關(guān)鍵字一樣。所以不能和存儲類的關(guān)鍵字一起使用:
錯誤的原因就是不能聲明多個存儲類關(guān)鍵字, typedef 已經(jīng)申明了存儲屬性,不允許再有第二個了。這個坑還是不容易跳進(jìn)去的,畢竟編譯器能幫你找出問題來,不用你擔(dān)心。