前言
這篇重點介紹一下代碼編程規范的擴展要求-表達式和基本語句規范要求
要求
【規范1】賦值語句不要寫在if
等語句中,或者作為函數的參數使用
因為
if
語句中,會根據條件依次判斷,如果前一個條件已經可以判定整個條件,則后續條件語句不會再運行,所以可能導致期望的部分賦值沒有得到運行如:if (test == 15 || HandleLogicFun()) {...}
,此時若test = 15
,則函數HandleLogicFun
就不會執行
【規范2】用括號明確表達式的操作順序,避免過分依賴默認優先級
使用括號強調所使用的操作符,防止因默認的優先級與設計思想不符而導致程序出錯;
同時使得代碼更為清晰可讀,然而過多的括號會分散代碼使其降低了可讀性。
一般代碼行的運算符比較多就需要,如果很簡單必要性不大,反而降低了美觀性
復合表達式
【規范1】不要編寫太復雜的符合表達式
太復雜的符合表達式不利于代碼閱讀如
i = a >= b && c < d && c + f <= g + h
,過于復雜
【規范2】不要有多用途的符合表達式
如
d = (a = b + c) + r
該表達式既求a
值又求d
值,應該拆分兩個獨立的語句:
a = b + c;
d = a + r;
if 語句
【規范1】布爾變量與零值比較
不可將布爾變量直接與
TRUE
、FALSE
或者1
、0
進行比較,雖然基本不會有什么大問題,但是會影響閱讀性根據布爾類型的語義,零值為“假” (記為FALSE
) ,任何非零值都是“真” (記為TRUE
) 。TRUE
的值究竟是什么并沒有統一的標準,例如 Visual C++ 將TRUE
定義為1
,而 Visual Basic 則將TRUE
定義為-1
;因此對于布爾變量,它與零值比較的標準if
語句如下:
if (flag) // 表示 flag 為真
{
}
if (!flag) // 表示 flag 為假
{
}
【規范2】整型變量與零值比較
應當將整型變量用
==
或!=
直接與0
比較。對于整型變量,它與零值比較的標準if
語句如下:
if (flag == 0)
{
}
if (flag != 0)
{
}
【規范3】浮點變量與零值比較
不可將浮點變量用
==
或!=
與任何數字比較。千萬要留意,無論是float
還是double
類型的變量,都有精度限制。所以一定要避免將浮點變量用==
或!=
與數字比較,應該設法轉化成>=
或<=
形式。假設浮點變量的名字為x
,應當將if (x == 0.0)
// 隱含錯誤的比較轉化為
if ((x >= -EPSINON) && (x <= EPSINON))
{
...
}
【規范4】指針變量與零值比較
應當將指針變量用
==
或!=
與NULL
比較,雖然和0
比較基本不會有什么大問題,但是會影響閱讀性,誤以為該變量是其它類型指針變量的零值是“空” (記為NULL
) 。盡管NULL
的值與0
相同,但是兩者意義不同。假設指針變量的名字為p
,它與零值比較的標準if
語句如下:
if (p == NULL) // p 與 NULL 顯式比較,強調 p 是指針變量
{
}
if (p != NULL)
{
}
【規范5】若if
有else if
分支,則必須有else
分支
雖然沒有
else
分支,但是在以后的代碼維護中能清楚表明自己考慮了這種情況,但是目前不需要做任何處理
if (...)
{
...
}
else if (...)
{
...
}
else
{
// TODO
}
其中表明注釋 “TODO” 說明表明自己考慮了這種情況,但是目前不需要做任何處理
【規范6】對于if ("變量" == "常量")
通常建議寫成if ("常量" == "變量")
好處時能避免粗心大意寫成
if ("變量" = "常量")
,而編譯可能不會報錯,最終代碼運行時就會出現異常,而if ("常量" == "變量")
這種寫法若少了=
,根據常量不能被賦值的規則,編譯時就會報錯。當然這種寫法可能不美觀,如果強迫癥,那建議養成習慣后可以再恢復if ("變量" = "常量")
這種寫法,因為寫該語句時都會下意識想到該規則,從而避免少寫=
,也能避免粗心引起的該問題。
if (5 == test)
{
}
if (NULL == pTest)
{
}
for/while/do 循環語句
循環語句有for
語句,while
語句,do
語句,其中for
語句是使用頻率最高的,以下規范1、2介紹如何提高for
循環語句的效率,其根本是降低循環體的復雜性。【規范1】在多重循環中,如果有可能,應當將最長的循環放在最內層,最短的循環放在最外層,以減少CPU跨切循環層的次數
其中第二種就比第一種的運行效率要高,光從C代碼角度看,區別不大,這個需要從匯編的角度看才能明顯看出,具體可以自行嘗試看執行時間(循環次數足夠)看或者網上百度兩種方式的對比,這里不再描述,網上比較詳細;不過我建議是直接看兩種編譯后的匯編語句,這樣感觸最深。
// 第一種
for (i = 0; i < 100; i++)
{
for (j = 0; j < 10; j++)
{
...
}
}
// 第二種
for (i = 0; i < 10; i++)
{
for (j = 0; j < 100; j++)
{
...
}
}
【規范2】循環中存在判斷語句等,根據實際情況選擇
如以下代碼中判斷表達式在循環體中,第二種就效率來說比第一種高,但是就代碼簡潔性來看,第一種更好,那么如何取舍呢?
循環次數較少,可以采用第一種,原因是在循環次數較少的情況下,第二種的效率提高不明顯
底層驅動開發時,采用第一種往往會極大地影響效率,所以普遍采用第二種(之前開發LCD驅動時,畫點時第二種比第一種在速度上明顯提高)
// 第一種
for (i = 0; i < 10; i++)
{
if (...)
{
...
}
else
{
...
}
}
// 第二種
if (...)
{
for (i = 0; i < 10; i++)
{
...
}
}
else
{
for (i = 0; i < 10; i++)
{
...
}
}
【規范3】不能再for
循環體內修改循環變量,防止for
循環失去控制
下列代碼容易失去控制
for (i = 0; i < 10; i++)
{
if (...)
{
i += 2;
}
else
{
...;
}
}
【規范4】建議for
循環控制變量的取值采用“半開半閉區間”原則
以下兩種方式功能一樣,但是第一種的寫法更加直觀
// 第一種
for (i = 0; i < N; i++)
{
...
}
// 第二種
for (i = 0; i <= N - 1; i++)
{
...
}
【規范5】空循環也應該使用{}
或者continue
,而不是一個簡單的分號
這樣做的目的是直觀地看出是一個空循環體
for (i = 0; i < N; i++)
{
}
while (flag)
{
condition;
}