1. 程式人生 > >讀書筆記--C陷阱與缺陷(二)

讀書筆記--C陷阱與缺陷(二)

ase 結果 erro bit 使用 功能 錯誤 多層 gnu

第二章

1. 理解函數聲明

書中分析了復雜的類型聲明方式,也說明了使用typedef聲明會更好理解,推薦大家使用typedef進行函數聲明。

書中類型分析一層一層挖掘,讓讀者可以理解多層嵌套的類型含義,有時間的讀者可以去看看,筆者不再重復。

既然書中推薦使用typedef進行函數聲明,我們就來研究下typedef:

typedef主要用於定義一種類型/結構體的別名。

從字面上看和C的宏定義 #define 挺像的,但是define只是簡單的參數替換,如果不註意括號很容易產生預期之外的錯誤。

在指針類型聲明時最好使用typedef,如下:

typedef char* PCHAR;

#define dpchar char*;

PCHAR p1,p2;

dpchar p3,p4;

上述語句中,p1,p2,p3可以被成功定義為char*,但是p4被定義為char(char* p3,p4;)。

對於結構體,一般定義為:

typedef struct STUDENT_ST

{

int id;

char name;

} student;

student st1;//代替struct STUDENT_ST st1,聲明更加簡單

typedef可高效解決平臺無關的數據類型,這對公司非常重要,因為不同的項目背景可能使用的系統平臺不盡相同,統一的管理數據類型可以避免錯誤。

如 typedef long double LONGNUM;

或 typedef long LONGNUM;

在跨平臺時就可以通過修改typedef來切換數據類型,而不用修改源碼,想象下如果修改每個源碼裏的類型該是多大的工程。。。

其實,還可以結合typedef使用bit field方式自定義字節長度的類型,下次有機會詳細說明吧~~

typedef另一個使用較多的就是書中提到的聲明復合類型:

如書中:(* (void (*) ()) 0) ();

可以改寫為:typedef void (*pfun) ();

(* (pfun) 0) ();

2. 運算符優先級

其實記不清運算符優先級的時候怎麽辦,加括號唄,最多就是括號多了理解起來費時點~

來看看書中推薦的優先級記法:

第一優先級: () [] -> .

其實是括號和調用操作符,很好理解,書中認為不用記,確實如此!

第二優先級: ! ~ ++ -- - (type) * & sizeof

由於第一優先級好理解,單目運算符可認為是最高優先級。

但要註意兩點:

  1. 對於 *p() ,因為第一優先級更高所以被解釋為 *(p()),要正確調用指針p指向的函數應為 (*p)() 。
  2. 單目運算符是自右向左結合的(與人看文字方向相反)。所以如 *p++ 會被解釋為*(p++),加1的是p值;寫為 (*p)++,加1的是p指向對象的值;雖然都是取出p指向對象的值。。。。

第三優先級: * / % - + (算術運算符)

第四優先級: << >> (移位運算符)

第五優先級: < <= > >= == != (關系/比較運算符)

第六優先級: & | ^ (邏輯/位運算符)

第七優先級: && || (邏輯運算符)

第八優先級: ? : (條件運算符)

註意:關系/比較運算符中,== != 的優先級低於其他關系運算符。如書中例子: a < b == c < d 即 (a<b) == (c<d)

邏輯運算符優先級也不相同,一般是”與”>”或”,即 &>^>|>&&>||

所有的賦值運算符(=)優先級一樣,但是自右向左結合!!

3. 註意分號

主要註意if while struct聲明。其實這些都比較簡單,但是筆者確實遇到過這種問題,當時筆者在if();後加了分號,程序結果一直不對但是檢查了很久才發現。。。

struct聲明後緊跟函數聲明時缺少分號很危險,書中提到編譯器會把聲明類型視為函數的返回值類型。如:

1 struct rec
2 {
3     int date;
4     int time;
5 }
6 main()
7 {
8     ...
9 }

struct rec的聲明結尾沒有分號,可能變為main函數的返回類型。。。

筆者對該程序進行了build,出現了兩個warning和1個error:

技術分享

第一個warning說:main函數的返回類型不是int;

第二個warning說:控制到達非void函數的結尾。通俗說就是應該帶有返回值的函數結尾可能無返回值。

error說:類型不匹配,當要返回int卻要求返回struct rec

看來優秀的IDE(codeblocks)還是可以避免這類錯誤的!

4. switch語句

書中強調C語言的switch語句能依次通過並執行各個case部分,所以若只想執行一個case要加break;

如:switch (color)

{

case 1 : printf(“red”);

case 2 : printf(“yellow”);

case 1 : printf(“blue”);

}

假設color取值2,最後程序打印 yellowblue

因為case2,case3都執行了,所以要加break;

當然如果你想通過刻意去掉break;來實現某些功能,可以這麽寫,但是代碼閱讀起來容易產生疑問。

讀書筆記--C陷阱與缺陷(二)