第七章 C語言宣告詳解

2021-06-01 10:45:52 字數 3283 閱讀 1454

人們常說,c語言的宣告太複雜了,的確,這也是c語言飽受批評的地方之一。不過,筆者認為,真正要受到批評的不是語言本身,而是那些傳播者。傳播者們通常都有乙個共識:講述要由淺入深。作為原則,筆者並非要反對它,畢竟筆者對c語言的學習,也經歷了相同的過程。但是,由淺入深並不意味著一切從簡,以偏蓋全。計算機語言不同於數學理論(雖然它的確根植於數學,與數學密不可分),數學理論是一種循序漸進的過程,後面的理論以前面的理論為基礎。但c語言歸根說底,就是一堆語言規則而已,應該讓學習者一開始就全面且詳細地了解它,而不是象現在某些教材所做的那樣,只說一部分,不說另一部分,以為這就是由淺入深了,實際上這是以偏蓋全。

語言如此,宣告作為c語言的一部分更是如此。我們最常見到的對宣告的描述是這樣的:

儲存類別  型別限定詞  型別  識別符號

這種說明會給人們一種暗示:c語言的宣告是靜止的、死板的,什麼宣告都能夠以這個為基礎,往上一套就ok了。事實真的如此嗎?說句心裡話,筆者也祈禱事實真的如此,這樣世界就簡單多了、清靜多了。但別忘了,這個世界總是讓人事與願違的。實際上,c的宣告的組織形式是以巢狀為基礎的,是用巢狀宣告組織起來的,並非象上面所述那麼死板,儲存類說明符一定得放在限定詞前面嗎?型別說明符一定要緊貼識別符號嗎?不!c標準從來沒有這樣說過!下面來看一看c89對宣告的形式是如何規定的:

宣告:宣告說明符   初始化宣告符表opt  [opt的意思是option,可選]

其中宣告說明符由以下三項構成:

宣告說明符:

儲存類說明符  宣告說明符opt

型別說明符    宣告說明符opt

型別限定符    宣告說明符opt

在這裡,乙個宣告說明符可以包含另乙個宣告說明符,這就是宣告的巢狀,這種巢狀貫穿於整個宣告之中,今天我們看來乙個非常簡單的宣告,其實就是由多個宣告巢狀組成的,例如:

static const int i=10, j=20, k=30;

變數i前面就是宣告說明符部分,有三個宣告說明符:static const int,static是乙個儲存類說明符,它屬於這種形式:

static 宣告說明符

static後面的宣告說明符就是const int,const是乙個型別限定符,這也是個巢狀,它是由

const 宣告說明符

組成,最後的int是乙個型別說明符,到這裡已經沒有巢狀了,int就是最底的一層。對於儲存類說明符、型別說明符和型別限定符的排列順序,c標準並沒有規定其順序,誰巢狀誰都可以。換言之,上面的宣告可以寫成:

int static const i=10, j=20, k=30;或者const int static i=10, j=20, k=30;

這無所謂,跟原宣告是一樣的。再舉乙個有趣的例子:

const int *p;與int const *p;

有些人會對後面一種形式感到困惑,因為他一直以來學習的都是那種死板的形式,因此他無法理解為什麼那個const可以放在int的後面。實際上對於標準來說,這是再正常不過的行為了。

上面舉的例子是變數的宣告,函式的宣告也同樣道理,例如:

static const int func(void);

......

int main(void)

const int static func(void)

func的函式原型宣告、函式定義跟main內的函式指標p的宣告是一樣的。但是,筆者並非鼓勵大家把宣告說明符寫得亂七八糟,作為乙個良好的風格,應該按照已經習慣約定的方式排列說明符,但懂得其中的原理非常重要。

宣告static const int i=10, j=20, k=30;的int後面的部分就是初始化宣告符表,這比較容易理解,這個符表實際上也是巢狀的:

初始化宣告符表:

初始化宣告符

初始化宣告符表, 初始化宣告符

初始化宣告符:

宣告符宣告符=初值

宣告符是初始化宣告符的主體,現在來討論一下宣告符是如何規定的:

宣告符:

指標opt  直接宣告符

這裡寫的指標opt指的是那個指標宣告符*,要注意的是,*屬於宣告符,而不是宣告說明符的一部分。

指標opt又包含:

指標:* 型別限定符表opt

* 型別限定符表opt 指標

在這裡有乙個常見的問題,就是const int *p;與int * const p的區別,第乙個宣告的const屬於宣告說明符,它跟int一起,是用來說明*p這個宣告符的,因此const修飾的是p所指向的那個物件,這個物件是const的。而第二個宣告的const是宣告符的一部分,它修飾的物件是p本身,因此p是const的。

上面規定的第二條值得注意,這條規定產生了一種指標與const的複雜形式,例如:

const int * const *** const ** const p;(是不是有種想衝向廁所的衝動?)這是一種複雜的宣告巢狀,如何解讀這種宣告?其實只要掌握了它的規律,無論它有多少個const、多少個*都不難解讀的,這個內容我將在第九章進行解釋。

剩下的就是直接宣告符和型別限定詞表的內容:

直接宣告符:

識別符號(宣告符)

直接宣告符[常量表示式opt]

直接宣告符(形式引數型別表)

直接宣告符(識別符號表opt)

型別限定符表:

型別限定符

型別限定符表 型別限定符

這一章的最後乙個內容,是討論一下typedef,typedef用來宣告乙個別名,typedef後面的語法,是乙個宣告。本來筆者以為這裡不會產生什麼誤解的,但結果卻出乎意料,產生誤解的人不在少數。罪魁禍首又是那些害人的教材。在這些教材中介紹typedef的時候通常會寫出如下形式:

typedef int para;

這種形式跟#define int para幾乎一樣,如前面幾章所述,這些教材的宗旨是由淺入深,但實際做出來的行為卻是以偏蓋全。的確,這種形式在所有形式中是最簡單的,但卻沒有對typedef進一步解釋,使得不少人用#define的思維來看待typedef,把int與para分開來看,int是一部分,para是另一部分,但實際上根本就不是這麼一回事。int與para是乙個整體!就象int i:宣告一樣是乙個整體宣告,只不過int i定義了乙個變數,而typedef定義了乙個別名。這些人由於持有這種錯誤的觀念,就會無法理解如下一些宣告:

typedef int a[10];

typedef void (*p)(void);

他們會以為a[10]是int的別名,(*p)(void)是void的別名,但這樣的別名看起來又似乎不是合法的名字,於是陷入困惑之中。實際上,上面的語句把a宣告為具有10個int元素的陣列的型別別名,p是一種函式指標的型別別名。

雖然在功能上,typedef可以看作乙個跟int para分離的動作,但語法上typedef屬於儲存類宣告說明符,因此嚴格來說,typedef int para整個是乙個完整的宣告。

第七章 C語言宣告詳解

人們常說,c語言的宣告太複雜了,的確,這也是c語言飽受批評的地方之一。不過,筆者認為,真正要受到批評的不是語言本身,而是那些傳播者。傳播者們通常都有乙個共識 講述要由淺入深。作為原則,筆者並非要反對它,畢竟筆者對c語言的學習,也經歷了相同的過程。但是,由淺入深並不意味著一切從簡,以偏蓋全。計算機語言...

C語言 第七章

一 在計算機中,位 bit 是表示和儲存資訊的最小單位,1b 8bit。c 語言提供一種在位一級進行操作的機制。它允許在乙個結構體中以位為單位來指定其成員所佔記憶體的長度,這種以位為單位的成員稱為 位段 或 位域 例如 struct a unsigned aa 1 unsigned bb 1 uns...

C語言第七章(7 1 7 4)

7.3 呼叫函式 7.3.2 函式呼叫時的資料傳遞 7.1 為什麼要用函式 7.3 呼叫函式 7.3.4 函式的返回值 7.4 對被呼叫函式的宣告和函式原型 執行結果 在這裡插入描述 how do you do include intmain void print star void print m...