今天人們越來越明白軟件設計更多地是一種工程,而不是一種個人藝術。由於大型產品的開發通常由很多的人協同作戰,如果不統一編程規范,最終合到一起的程序,其可讀性將較差,這不僅給代碼的理解帶來障礙,增加維護階段的工作量,同時不規范的代碼隱含錯誤的可能性也比較大。
BELL實驗室的研究資料表明,軟件錯誤中18%左右產生於概要設計階段,15%左右產生於詳細設計階段,而編碼階段產生的錯誤占的比例則接近50%;分析表明,編碼階段產生的錯誤當中,語法錯誤大概占20%左右,而由於未嚴格檢查軟件邏輯導致的錯誤、函數(模塊)之間接口錯誤及由於代碼可理解度低導致優化維護階段對代碼的錯誤修改引起的錯誤則占了一半以上。
可見,提高軟件質量必須降低編碼階段的錯誤率。如何有效降低編碼階段的錯誤呢?BELL實驗室的研究人員制定了詳細的軟件編程規范,並培訓每一位程序員,最終的結果把編碼階段的錯誤降至10%左右,同時也降低了程序的測試費用,效果相當顯著。
本文從代碼的可維護性(可讀、可理解性、可修改性)、代碼邏輯與效率、函數(模塊)接口、可測試性四個方面闡述了軟件編程規范,規范分成規則和建議兩種,其中規則部分為強制執行項目,而建議部分則不作強制,可根據習慣取捨。
2. 編碼規范
2.1. 排版風格
<規則 1> 程序塊采用縮進風格編寫,縮進為4個空格位。排版不混合使用空格和TAB鍵。
<規則2> 在兩個以上的關鍵字、變量、常量進行對等操作時,它們之間的操作符之前、之後或者前後要加空格;進行非對等操作時,绻槍叵得芮械牧⒓床僮鞣ㄈ纾?gt;),後不應加空格。
采用這種松散方式編寫代碼的目的是使代碼更加清晰。例如:
(1) 逗號、分號只在後面加空格
printf("%d %d %d" , a, b, c);
(2)比較操作符, 賦值操作符"="、 "+=",算術操作符"+"、"%",邏輯操作符"&&"、"&",位域操作符"<<"、"^"等雙目操作符的前後加空格
if(lCurrentTime >= MAX_TIME_VALUE)
a = b + c;
a *= 2;
a = b ^ 2;
(3)"!"、"~"、"++"、"--"、"&"(地址運算符)等單目操作符前後不加空格
*pApple = ''a''; // 內容操作"*"與內容之間
flag = !bIsEmpty; // 非操作"!"與內容之間
p = &cMem; // 地址操作"&" 與內容之間
i++; // "++","--"與內容之間
(4)"->"、"."前後不加空格
p->id = pId; // "->"指針前後不加空格
由於留空格所產生的清晰性是相對的,所以,在已經非常清晰的語句中沒有必要再留空格,如最內層的括號內側(即左括號後面和右括號前面)不要加空格,因為在 C/C++語言中括號已經是最清晰的標志了。8BR>另外,在長語句中,如果需要加的空格非常多,那麼應該保持整體清晰,而在局部不加空格。
最後,即使留空格,也不要連續留兩個以上空格(為了保證縮進和排比留空除外)。
<規則3> 函數體的開始,類的定義,結構的定義,if、for、do、while、switch及case語句中的程序都應采用縮進方式,憑捄蛻}捰禀獨占一行並且位於同一列,同時與引用它們的語句左對齊
例如下例不符合規范。
for ( ... ) {
... // 程序代碼
}
if ( ... )
{
... // 程序代碼
}
void DoExam( void )
{
... // 程序代碼
}
應如下書寫。
for ( ... )
{
... // 程序代碼
}
if ( ... )
{
... // 程序代碼
}
void DoExam( void )
{
... // 程序代碼
}
<規則4> 功能相對獨立的程序塊之間或for、if、do、while、switch等語句前後應加一空行。
例如以下例子不符合規范。
例一:
if ( ! ValidNi( ni ) )
{
... // 程序代碼
}
nRepssnInd = SsnData[ index ].nRepssnIndex ;
nRepssnNi = SsnData[ index ].ni ;
例二:
char *pContext;
int nIndex;
long lCounter;
pContext = new (CString);
if(pContext == NULL)
{
return FALSE;
}
應如下書寫
例一:
if ( ! ValidNi( ni ) )
{
... // 程序代碼
}
nRepssnInd = SsnData[ index ].nRepssnIndex ;
nRepssnNi = SsnData[ index ].ni ;
例二:
char *pContext;
int nIndex;
long lCounter;
pContext = new (CString);
if(pContext == NULL)
{
return FALSE;
}
<規則5> if、while、for、case、default、do等語句自占一行。
示例:如下例子不符合規范。
if(pUserCR == NULL) return;
應如下書寫:
if( pUserCR == NULL )
{
return;
}
<規則6> 若語句較長(多於80字符),可分成多行寫,劃分出的新行要進行適應的縮進,使排版整齊,語句可讀。
memset(pData->pData + pData->nCount, 0,
(m_nMax - pData->nCount) * sizeof(LPVOID));
CNoTrackObject* pValue =
(CNoTrackObject*)_afxThreadData->GetThreadValue(m_nSlot);
for ( i = 0, j = 0 ; ( i < BufferKeyword[ WordIndex ].nWordLength )
&& ( j < NewKeyword.nWordLength ) ; i ++ , j ++ )
{
... // 程序代碼
}
<規則7> 一行最多寫一條語句。
示例:如下例子不符合規范。
rect.length = 0 ; rect.width = 0 ;
rect.length = width = 0;
都應書寫成:
rect.length = 0 ;
rect.width = 0 ;
<規則8> 對結構成員賦值,等號對齊。