規范的代碼可以促進團隊合作,一個項目大多都是由一個團隊來完成,如果沒有統一的代碼規范,那么每個人的代碼必定會風格迥異,等到要整合代碼的時候也有夠頭疼的了。
我認為,編碼規范,在軟件構件以及項目管理中,甚至是個人成長方面,都發揮著重要的作用,好的編碼規范是提高我們代碼質量的最有效的工具之一。
幾乎每個項目,每家公司都會定義自己的編碼規范,我們可以參考一下華為公司C/C++的編碼規范。
1、代碼排版
1、程序塊要采用縮進風格編寫,縮進的空格數為4個(說明:對于由開發工具自動生成的代碼可以有不一致)。
2、相對獨立的程序塊之間、變量說明之后必須加空行。
3、循環、判斷等語句中若有較長的表達式或語句,則要進行適應的劃分,長表達式要在低優先級操作符處劃分新行,操作符放在新行之首。
4、若函數或過程中的參數較長,則要進行適當的劃分。
5、不允許把多個短語句寫在一行中,即一行只寫一條語句。
6、if、for、do、while、case、switch、default等語句自占一行,且if、for、do、while等語句的執行語句部分無論多少都要加括號{}。
7、對齊只使用空格鍵,不使用TAB鍵。8、函數或過程的開始、結構的定義及循環、判斷等語句中的代碼都要采用縮進風格,case語句下的情況處理語句也要遵從語句縮進要求。
9、程序塊的分界符(如C/C++語言的大括號‘{’ 和‘}’)應各獨占一行并且位于同一列,同時與引用它們的語句左對齊。在函數體的開始、類的定義、結構的定義、枚舉的定義以及if、for、do、while、switch、case語句中的程序都要采用如上的縮進方式。
10、在兩個以上的關鍵字、變量、常量進行對等操作時,它們之間的操作符之前、之后或者前后要加空格;進行非對等操作時,如果是關系密切的立即操作符(如-》),后不應加空格(說明:采用這種松散方式編寫代碼的目的是使代碼更加清晰)。
注意:(1)由于留空格所產生的清晰性是相對的,所以,在已經非常清晰的語句中沒有必要再留空格,如果語句已足夠清晰則括號內側(即左括號后面和右括號前面)不需要加空格,多重括號間不必加空格,因為在C/C++語言中括號已經是最清晰的標志了。
(2)在長語句中,如果需要加的空格非常多,那么應該保持整體清晰,而在局部不加空格。給操作符留空格時,不要連續留兩個以上空格。
2、代碼注釋 1、一般情況下,源程序有效注釋量必須在20%以上(說明:注釋的原則是有助于對程序的閱讀理解,在該加的地方都加了,注釋不宜太多也不能太少,注釋語言必須準確、易懂、簡潔)。
2、說明性文件(如頭文件.h文件、.inc文件、.def文件、編譯說明文件.cfg等)頭部應進行注釋,注釋必須列出:版權說明、版本號、生成日期、作者、內容、功能、與其它文件的關系、修改日志等,頭文件的注釋中還應有函數功能簡要說明。
3、源文件頭部應進行注釋,列出:版權說明、版本號、生成日期、作者、模塊目的/功能、主要函數及其功能、修改日志等。
4、函數頭部應進行注釋,列出:函數的目的/功能、輸入參數、輸出參數、返回值、調用關系(函數、表)等。
示例:
下面這段函數的注釋比較標準,當然,并不局限于此格式,但上述信息建議要包含在內。
? Function: // 函數名稱
? Description: // 函數功能、性能等的描述
? Calls: // 被本函數調用的函數清單
? Called By: // 調用本函數的函數清單
? Table Accessed: // 被訪問的表(此項僅對于牽扯到數據庫操作的程序)
? Table Updated: // 被修改的表(此項僅對于牽扯到數據庫操作的程序)
? Input: // 輸入參數說明,包括每個參數的作用、取值說明及參數間關系
? Output: // 對輸出參數的說明
? Return: // 函數返回值的說明
5、邊寫代碼邊注釋,修改代碼同時修改相應的注釋,以保證注釋與代碼的一致性;不再有用的注釋要刪除。
6、注釋的內容要清楚、明了,含義準確,防止注釋二義性。
7、避免在注釋中使用縮寫,特別是非常用縮寫。
8、注釋應與其描述的代碼相近,對代碼的注釋應放在其上方或右方(對單條語句的注釋)相鄰位置,不可放在下面,如放于上方則需與其上面的代碼用空行隔開。
9、對于所有有物理含義的變量、常量,如果其命名不是充分自注釋的,在聲明時都必須加以注釋,說明其物理含義。變量、常量、宏的注釋應放在其上方相鄰位置或右方。
10、數組、結構、類、枚舉等,如果其命名不是充分自注釋的,必須加以注釋。對數據結構的注釋應放在其上方相鄰位置,不可放在下面;對結構中的每個域的注釋放在此域的右方。
11、全局變量要有較詳細的注釋,包括對其功能、取值范圍、哪些函數或過程存取它以及存取時注意事項等的說明。
12、注釋與所描述內容進行同樣的縮排。
13、將注釋與其上面的代碼用空行隔開。
14、函數的頭部應進行注釋,列出函數的功能、目的、輸入輸出參數、返回值、調用關系(表、函數)等。
15、對變量的定義和分支語句(條件分支、循環語句等)必須編寫注釋。
16、對于switch語句下的case語句,如果因為特殊情況需要處理完一個case后進入下一個case處理,必須在該case語句處理完、下一個case語句前加上明確的注釋。
3、標識符命名 1、標識符的命名要清晰、明了,有明確含義;同時,使用完整的單詞或大家基本可以理解的縮寫,避免使人產生誤解(說明:較短的單詞可通過去掉“元音”形成縮寫;較長的單詞可取單詞的頭幾個字母形成縮寫;一些單詞有大家公認的縮寫)。示例:如下單詞的縮寫能夠被大家基本認可:? temp可縮寫為 tmp; 臨時? flag可縮寫為 flg; 標志? statistic可縮寫為 stat ; 統計? increment可縮寫為 inc; 增量? message可縮寫為 msg; 消息
2、命名中若使用特殊約定或縮寫,則要有注釋說明(說明:應該在源文件的開始之處,對文件中所使用的縮寫或約定,特別是特殊的縮寫,進行必要的注釋說明)。
3、自己特有的命名風格,要自始至終保持一致,不可來回變化(說明:個人的命名風格,在符合所在項目組或產品組的命名規則的前提下才可使用,即命名規則中沒有規定到的地方才可有個人命名風格)。
4、對于變量命名,禁止取單個字符(如i、j、k…),建議除了要有具體含義外,還能表明其變量類型、數據類型等,但i、j、k作局部循環變量是允許的。
說明:變量,尤其是局部變量,如果用單個字符表示,很容易敲錯(如i寫成j),而編譯時又檢查不出來,有可能為了這個小小的錯誤而花費大量的查錯時間。
5、命名規范必須與所使用的系統風格保持一致,并在同一項目中統一,比如采用UNIX的全小寫加下劃線的風格或大小寫混排的方式,不要使用大小寫與下劃線混排的方式,用作特殊標識如標識成員變量或全局變量的m_ 和g_ ,其后加上大小寫混排的方式是允許的。
4、代碼可讀性1、注意運算符的優先級,并用括號明確表達式的操作順序,避免使用默認優先級。2、避免使用不易理解的數字,用有意義的標識來替代。涉及物理狀態或者含有物理意義的常量,不應直接使用數字,必須用有意義的枚舉或宏來代替。
5、變量、結構 1、去掉沒必要的公共變量(說明:公共變量是增大模塊間耦合的原因之一,故應減少沒必要的公共變量以降低模塊間的耦合度)。
2、仔細定義并明確公共變量的含義、作用、取值范圍及公共變量間的關系(說明:在對變量聲明的同時,應對其含義、作用及取值范圍進行注釋說明;同時,若有必要,還應說明與其它變量的關系)。
3、明確公共變量與操作此公共變量的函數或過程的關系,如訪問、修改及創建等(說明:明確過程操作變量的關系后,將有利于程序的進一步優化、單元測試、系統聯調以及代碼維護等,這種關系的說明可在注釋或文檔中描述)。
示例:在源文件中,可按如下注釋形式說明。? RELATION System_Init Input_Rec Print_Rec Stat_Score? Student Create Modify Access Access? Score Create Modify Access Access, Modify注意:RELATION為操作關系;System_Init、Input_Rec、Print_Rec、Stat_Score為四個不同的函數;Student、Score為兩個全局變量;Create表示創建,Modify表示修改,Access表示訪問。其中,函數Input_Rec、Stat_Score都可修改變量Score,故此變量將引起函數間較大的耦合,并可能增加代碼測試、維護的難度。
4、當向公共變量傳遞數據時,要十分小心,防止賦與不合理的值或越界等現象發生(說明:對公共變量賦值時,若有必要應進行合法性檢查,以提高代碼的可靠性、穩定性)。
5、防止局部變量與公共變量同名(說明:若使用了較好的命名規則,那么此問題可自動消除)。
6、嚴禁使用未經初始化的變量作為右值(說明:特別是在C/C++中引用未經賦值的指針,經常會引起系統崩潰)。
6、函數與過程 1、對所調用函數的錯誤返回碼要仔細、全面地處理。
2、明確函數功能,精確(而不是近似)地實現函數設計。
3、編寫可重入函數時,應注意局部變量的使用(如編寫C/C++語言的可重入函數時,應使用auto,即缺省態局部變量或寄存器變量)。
說明:編寫C/C++語言的可重入函數時,不應使用static局部變量,否則必須經過特殊處理,才能使函數具有可重入性。
4、編寫可重入函數時,若使用全局變量,則應通過關中斷、信號量(即P、V操作)等手段對其加以保護。
說明:若對所使用的全局變量不加以保護,則此函數就不具有可重入性,即當多個進程調用此函數時,很有可能使有關全局變量變為不可知狀態。
示例:
假設Exam是int型全局變量,函數Squre_Exam返回Exam平方值。那么,如下函數不具有可重入性。
unsigned int example( int para )
{
unsigned int temp;
Exam = para; // ()
temp = Square_Exam( );
return temp;
}
此函數若被多個進程調用的話,其結果可能是未知的,因為當()語句剛執行完后,另外一個使用本函數的進程可能正好被激活,那么當新激活的進程執行到此函數時,將使Exam賦與另一個不同的para值,所以當控制重新回到“temp = Square_Exam( )”后,計算出的temp很可能不是預想中的結果。此函數應如下改進:
unsigned int example( int para )
{
unsigned int temp;[申請信號量操作] // 若申請不到“信號量”, 說明另外的進程正處于
Exam = para; // 給Exam賦值并計算其平方過程中(即正在使用此信號), 本進程必須等待其釋放信號后, 才可繼續執行。若申請到信號, 則可繼續執行, 但其它進程必須等待本進程釋放信號量后, 才能再使用本信號。
temp = Square_Exam( ); // [釋放信號量操作]
return temp;
}
5、在同一項目組應明確規定對接口函數參數的合法性檢查,該由函數的調用者負責,還是由接口函數本身負責,缺省是由函數調用者負責(說明:對于模塊間接口函數的參數的合法性檢查這一問題,往往有兩個極端現象,即:要么是調用者和被調用者對參數均不作合法性檢查,結果就遺漏了合法性檢查這一必要的處理過程,造成問題隱患;要么就是調用者和被調用者均對參數進行合法性檢查,這種情況雖不會造成問題,但產生了冗余代碼,降低了效率)。
7、程序效率 1、編程時要經常注意代碼的效率。
2、在保證軟件系統的正確性、可讀性、穩定性及可測試性的前提下,提高代碼效率。
3、對模塊中函數的劃分及組織方式進行分析、優化,改進模塊中函數的組織結構,提高程序效率。
4、編程時,要隨時留心代碼效率;優化代碼時,要考慮周全。
5、不應花過多的時間拼命地提高調用不很頻繁的函數代碼效率。
6、要仔細地構造或直接用匯編編寫調用頻繁或性能要求極高的函數。
7、在保證程序質量的前提下,通過壓縮代碼量、去掉不必要代碼,以及減少不必要的局部和全局變量,來提高空間效率。
8、在多重循環中,應將最忙的循環放在最內層。
9、盡量減少循環嵌套層次。
10、避免循環體內含判斷語句,應將循環語句置于判斷語句的代碼塊之中。
11、盡量用乘法或其他的方法代替除法,特別是浮點運算中的除法。
12、不要一味追求緊湊的代碼。
最后提醒一句,“任何一個傻瓜都能寫出計算機可以理解的代碼,唯有寫出人類容易理解的代碼,才是優秀的程序員。”制定一個符合自己公司情況的開發規范是很簡單的,重要的是我們能夠認識到規范的重要性,并堅持規范的開發習慣。
編輯:黃飛
評論
查看更多