C語言的設計哲學:對象的聲明形式和它的使用形式盡可能相似。例如: 指針數組定義為int *p[4],使用指針指向的int數據時寫成*p[i],他們形式相似。優點是:各種操作符的優先級在“聲明”和“使用”時是一樣的;缺點是:操作符的優先級太多相當復雜,無法以習慣的方式從左到右閱讀一個聲明來確定數據。
例如:
int * P[5] :指針數組(數據元素全為指針的數組),本質是一個數組,內容是指向int類型數據的指針(地址)。
int (*P) [5] :數組指針(指向數組的指針),本質是一個指針,指針的數據是一個由5個int數據組成的數組的首地址。
如果想要區分這兩個聲明,就必須了解*和[]的優先級,默認情況下*優先級低於[]。對於int * P[5],先看P[5]確定這是一個數組,再看int * 確定數組的內容是指向int的指針;對於int (*P) [5],由於括號的存在,先看括號裡邊的 *,確定這是一個指針P,再看int [5]確定指針指向的是一個由5個int數據組成的數組。C語言的優先級有15級之多,所以分析聲明類型是相當恐怖的。
const int * vol_ptr和int const * vol_ptr : 表示指針指向的數據是只讀的,輔助記憶:const在*左邊離數據比較近,故作用於數據上。
int * const vol_ptr :表示指針本身是只讀的,輔助記憶:const在*右邊離指針比較近,故作用於指針上。
1、結構體struct注意事項
結構的定義後面可以直接跟變量名,表示這些變量的類型是這個結構。例如:struct { *** } vol, rate ;這樣就定義了兩個結構體變量vol和rate。理解:跟基本類型變量的定義int number ;本質相同 ,可以認為 struct { *** } 就類似於系統內部類型定義int,只是類型不同而已。
缺點是:無法利用這個 struct{ *** } 再進行新的變量定義了。
解決方案就是:struct後邊增加“結構標簽”類似於struct tag { *** } ; 這樣以後再定義新變量時,直接用結構體標簽:struct tag vol , xxx,xxx, ……;
能不能再優化一點?用typedef進行類型定義,不過這樣就無法知道定義的某個變量是不是結構類型了。
結構中允許存在位段、無名字段以及字對齊所需的填充字段。通過在字段的聲明後面加一個冒號以及表示字段位長的整數來實現。
[cpp]
struct tag
{
unsigned int inactive :1;
unsigned int :1;
unsigned int test :6;
short pid_id;
struct tag * next;
}
位段的類型必須是int、unsigned int或signed int,int位段的值可不可以取負值取決於編譯器。而且盡量不要把結構體的聲明和變量的定義混在一起,這樣影響代碼閱讀。
2、聯合union注意事項
在聯合union中,所有的成員都從偏移地址零開始存儲,每個成員位置都重疊在一起,在某一時刻只有一個成員真正存儲於該地址。優點是:可以節省存儲空間;缺點是:需要程序員時刻牢記自己存儲的數據類型,以便用合理的方式解釋數據。
還有就是可以把同一種數據解釋成兩種不同的東西,尤其是在嵌入式硬件編程時使用較多。
例如:
[cpp]
union bit_tag
[cpp]
{
uint_8 state;
struct
{
uint_8 bit_1 :4;
uint_8 bit_2 :4;
}BIT;
[cpp]
}
3、枚舉enum注意事項
枚舉就是簡單的把一串名字和一串整型值聯系在一起。默認情況下,整型值從0開始,如果對表中某個標識符進行賦值,那麼緊接其後的那個標識符就比這個大1,依次類推,直到到達下一個手動賦值的數值開始,繼續依照新的基准值開始計數。
優點:#define定義的名字在編譯時就被丟棄了(預處理階段替換掉了),而枚舉名字在調試器中可見,可以在調試時使用。枚舉類型定義的變量,在系統中會有類型檢查,而#define則沒有,所以推薦用枚舉。