讀書筆記--C陷阱與缺陷(二)
第二章
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
由於第一優先級好理解,單目運算符可認為是最高優先級。
但要註意兩點:
- 對於 *p() ,因為第一優先級更高所以被解釋為 *(p()),要正確調用指針p指向的函數應為 (*p)() 。
- 單目運算符是自右向左結合的(與人看文字方向相反)。所以如 *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陷阱與缺陷(二)