C語言的聲明語法(聲明模型)很晦澀,容易成為程序員的障礙,正是由於在組合類型方面的笨拙行為,C語言顯得很復雜。
造成這種情況的原因是因為“類型模型(type model)”這個概念對於當時的編程語言理論而言尚屬陌生。BCPL(C語言前身)語言幾乎沒有類型,其以二進制字作為唯一的數據類型。 C語言的設計哲學之一:對象的聲明形式與它的使用形式要盡可能相似。 int *p[3]是一個int類型的指針數組。 其使用方法如下:* p[ a0[] = {, , a1[] = {, a2[] = {-, , , , p[] =] =] =( i = ; i < ; i++, p[]++ , *p[( i = ; i < ; i++, p[]++ , *p[( i = ; i < ; i++, p[]++ , *p[其執行結果如下: C語言的聲明所存在的最大問題是你無法以一種習慣性的從左向右的方式閱讀一個聲明。 關於const 指針所指向的對象是只讀的兩種聲明:
i [] = {, * grape ; * orange ; grape = &= & , *grape ); grape++; printf( , *grape );
指針本身是只讀的聲明:
i = * apple = &*apple += ; , *apple );
i = * grape_jam_1 = & * grape_jam_2 = &+= ; *grape_jam_1 += ;上面這段代碼所產生的錯誤如下: 總結的規則:在指針的聲明中,只要const“緊挨著”指針變量就說明該指針本身是只讀的,否則就是該指針所指向的對象是只讀的。
{ 內容 ... };結構的定義後可以跟一些變量名,表示這些變量的類型是這個結構:
{ 內容 ... } plum, pomegranate, pear ;struct關鍵字後可以加一個可選的“結構標簽”,可以作為結構的簡寫形式(structfruit_tag)用於以後定義變量:
fruit_tag { 內容... } plum, pomegranate , pear;因此,結構的通常形式: 作者建議不要把結構的聲明和變量的定義混合在一起,而是分開,使代碼更容易閱讀。 變量的聲明應該與類型的聲明分開。 兩個跟結構有關的參數傳遞問題: 第二點如下代碼所示:
a[]; s_tag twofold( ( j = ; j < ; j++*= ( i = ; i < ; i++= == lemon; }結構中包含一個指向結構本身的指針,這種方法常用於列表(list)、樹(tree)等。 關於聯合(union) 結構中每個成員依次存儲,而在聯合中,所有成員都成偏移量為0處開始存儲,在某一時刻,只有一個成員真正存儲於該地址。聯合因此也叫“變體記錄”。 聯合的一般形式: 聯合一般作為大型結構的一部分存在。用以節省存儲空間,因為某些數據項不可能同時出現。 聯合也可以把同一個數據解釋成兩種不同的東西,而不是把兩個不同的數據解釋為同一種東西。 作者最後列舉數據(15W行與機器無關的OS源代碼),說明結構出現的次數大約是聯合的一百倍。 關於枚舉(enum) 枚舉通過一種簡單的途徑,把一串名字與一串整型值聯系在一起。 對於C來說,很少有什麼事只能考枚舉來完成而無法用#define解決的。 枚舉的一版形式: 缺省情況下,整型值從0開始。如果對列表中的某個標識符進行了賦值,那麼後面的標識符依次大1。 枚舉與#define的一個不同:#define定義的名字一般在編譯時被丟棄,而枚舉名字通常在調試器中一直可見。
peach int2. 在連續幾個變量的聲明語句中,用typedef定義的類型能夠保證聲明中所有的變量均為同一種類型,而#define定義的類型則無法保證。
d_string char* *
typedef fruit mandarin;如上這種情況,結構標簽與typedef的結構別名具有了相同的名字,作者在此處建議:當你有兩個不同的東西時,一個比較好的原則就是用不同的名字來稱呼它們。這樣做減少了混淆的危險(這始終是軟件的一個重要准則)。比如此處可以在結構標簽後加一個"_tag"後綴。