为何不精通C? 03 深入剖析声明
??? 對(duì)于復(fù)雜的C函數(shù)聲明,或者被typedef別名后的聲明,很多人往往一頭霧水。本文主要解析下C語(yǔ)言中聲明過(guò)程所遵循的原則。
聲明
??? 引用《C專家編程》的第三章內(nèi)容,說(shuō)明下聲明的優(yōu)先級(jí)規(guī)則:
- ?括號(hào)包圍的地方
- 后綴操作符:
- 括號(hào)()表示是一個(gè)函數(shù)
- 方括號(hào)[]表示是一個(gè)數(shù)組
- 前綴操作符:星號(hào)*表示類型是 指向....的指針
不過(guò),我覺得這個(gè)規(guī)則的不夠通俗,看了《C++Annotation》中關(guān)于const的那一章節(jié),也詳細(xì)解釋了下這個(gè)規(guī)則,高效,庖丁解牛般分析:
// 例子char* const *(*next)();
通俗的乒乓解釋,就是從變量名開始,碰到)或結(jié)束往左讀,碰到(往右讀。
遇到*()[]解釋之
其中 解釋是函數(shù)的話,需解釋其形參表及返回值
?????? 解釋為數(shù)組的話,需解釋數(shù)組元素是什么
?????? 解釋為指針時(shí),需解釋其指向什么類型
舉例:
1 next 名叫next, 開始往右讀,碰到了),折向往左 2 (*next) 遇到* ,解釋是一個(gè)指針 繼續(xù)往左讀碰到(, 折向往右 3 (*next)() 遇到(),解釋指向一個(gè)函數(shù),該函數(shù)沒有形參 到末尾,折向往左4 *(*next)() 遇到*,解釋函數(shù)返回一個(gè)指針,關(guān)于函數(shù)的形參表和返回值解釋完畢 , 繼續(xù)往左 5 char* const *(*next)() 先碰到const,再是*, 最后是char, 解釋函數(shù)的返回值(指針)指向一個(gè)char型指針常量,即指針不可賦新值,所指的值可以改變。到開頭,結(jié)束。
以上的例子是函數(shù)的聲明舉例。
對(duì)其他的聲明也是一樣的,比如之前文章中? int *ap[], 我們也是這樣解釋的:
- 從 ap 開始往右讀,碰到了[], 說(shuō)明是一個(gè)數(shù)組
- 然后到末尾,折向向左,碰到*,說(shuō)明數(shù)組的元素是指針,
- 最后碰到int,說(shuō)明該元素的指針類型為 int*
常規(guī)的 const int * p; 也可以這么來(lái):
- 從 p 開始,結(jié)尾折向,往左走。
- 先碰到*, 說(shuō)明是一個(gè)指針
- 再碰到 int,const, const修飾的是int, 則說(shuō)明該指針指向一個(gè)const int東西
同理,對(duì)于 int* const p: 我們?cè)谕罂磿r(shí),先看到了const,再*, 說(shuō)明const修飾的是*。
來(lái)個(gè)復(fù)雜的挑戰(zhàn)下吧:
char* const* (* const (*(*ip)() ) [] ) [] (*ip) ip是一個(gè)指針 (*ip)() ip是一個(gè)函數(shù)指針,該函數(shù)無(wú)形參 *(*ip)() 函數(shù)返回一個(gè)指針 (...)[] 該指針指向一個(gè)數(shù)組 *const (...)[] 數(shù)組元素為 常量指針 (*const (...)[]) [] 該常量指針指向一個(gè)數(shù)組 char* const* {...}該數(shù)組內(nèi)元素為指向char型常量指針的指針 合起來(lái)就是:ip是一個(gè)函數(shù)指針(無(wú)形參), 返回一個(gè)指向數(shù)組的指針,該數(shù)組內(nèi)元素為常量指針,其指向一個(gè)元素為char型常量指針的數(shù)組。不過(guò),一般不會(huì)有這種聲明來(lái)惡心我們的。。我們基本上知道怎么打乒乓就行了。
typedef
剖析完了聲明,一般來(lái)說(shuō)還要說(shuō)下 typedef ,這可是C的一大神器呀。
首先,我們要明確的是,typedef是為類型創(chuàng)建別名,而不是創(chuàng)造新的類型。
講typedef時(shí),又必須和 #define做下區(qū)分, define僅是簡(jiǎn)單的宏擴(kuò)展
主要來(lái)說(shuō),有以下的區(qū)別:
- 首先,可以對(duì)其他類型說(shuō)明符采用宏類型名進(jìn)行擴(kuò)展,但對(duì)typedef所定義則不行
- 其次,連續(xù)變量聲明中,typedef能夠保證所有定義類型一致,而#define不能保證
和typedef做好朋友
void (*signal(int sig, void(*func)(int))) (int);
我們來(lái)分析下這個(gè)是什么東西:
??? signal(..) : signal 是一個(gè)函數(shù),有復(fù)雜的形參表
??? *signal(...) : 返回值是一個(gè)指針
??? void {*}(int) : 該指針指向一個(gè)函數(shù),該函數(shù)的形參為int, 這個(gè)函數(shù)的返回值是void
我們看看signal的形參表: 兩個(gè)參數(shù),一個(gè)參數(shù)是 int; 另外個(gè)參數(shù) void(*func)(int) 是一個(gè)函數(shù)指針,該函數(shù)有一個(gè)int形參,返回void;
對(duì)比下,我們可以分析出, signal的返回值和 func的定義一樣, 都是 void(*)(int), 但若是采用這種寫法的話,不好看懂,這時(shí)候,我們的好朋友typedef就出現(xiàn)了:
typedef void(*ptr_to_func)(int); ptr_to_func signal(int, ptr_to_func){.....}另外,typedef也經(jīng)常和struct配合使用。
typedef struct my_struct{....} NewName;這樣,NewName 就等同于 struct my_struct , 少打了struct這幾個(gè)字符
擴(kuò)展說(shuō)下 聲明和定義的區(qū)別:
C語(yǔ)言中,對(duì)象有且僅有一個(gè)定義,而聲明卻可以有多個(gè)extern 聲明。
定義:只能出現(xiàn)在一個(gè)地方,確定同時(shí)分配內(nèi)存,它是特殊的聲明
聲明:只是描述其他地方創(chuàng)建對(duì)象的屬性。有extern前綴,作用于變量
具體的一些擴(kuò)展區(qū)別,見后續(xù)博文,關(guān)于指針和數(shù)組的闡釋
END
要點(diǎn): 怎么打乒乓?typedef是個(gè)別名好朋友
轉(zhuǎn)載于:https://www.cnblogs.com/IntellX/archive/2013/05/17/3083701.html
總結(jié)
以上是生活随笔為你收集整理的为何不精通C? 03 深入剖析声明的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。