規范的代碼可以促進團隊合作,一個項目大多都是由一個團隊來完成,如果沒有統一的代碼規范,那么每個人的代碼必定會風格迥異,等到要整合代碼的時候也有夠頭疼的了。
我認為,編碼規范,在軟件構件以及項目管理中,甚至是個人成長方面,都發揮著重要的作用,好的編碼規范是提高我們代碼質量的最有效的工具之一。
幾乎每個項目,每家公司都會定義自己的編碼規范,我們可以參考一下華為公司C/C++的編碼規范。
1、代碼排版
1.1 程序塊要采用縮進風格編寫, 縮進的空格數為4個。(說明: 對于由開發工具自動生成的代碼可以有不一致)
1.2 相對獨立的程序塊之間、變量說明之后必須加空行。
1.3 循環、判斷等語句中若有較長的表達式或語句, 則要進行適應的劃分, 長表達式要在低優先級操作符處劃分新行, 操作符放在新行之首。
1.4 若函數或過程中的參數較長, 則要進行適當的劃分。
1.5 不允許把多個短語句寫在一行中, 即一行只寫一條語句。
1.6 if、for、do、while、case、switch、default等語句自占一行, 且if、for、do、while等語句的執行語句部分無論多少都要加括號{}。
1.7 對齊只使用空格鍵, 不使用TAB鍵。
1.8 函數或過程的開始、結構的定義及循環、判斷等語句中的代碼都要采用縮進風格, case 語句下的情況處理語句也要遵從語句縮進要求。
1.9 程序塊的分界符(如C/C++ 語言的大括號‘{’ 和‘}’ )應各獨占一行并且位于同一列, 同時與引用它們的語句左對齊。在函數體的開始、類的定義、結構的定義、枚舉的定義以及if、for、do、while、switch、case 語句中的程序都要采用如上的縮進方式。
1.10 在兩個以上的關鍵字、變量、常量進行對等操作時, 它們之間的操作符之前、之后或者前后要加空格; 進行非對等操作時, 如果是關系密切的立即操作符(如-》), 后不應加空格。(說明: 采用這種松散方式編寫代碼的目的是使代碼更加清晰。)
注:(1)由于留空格所產生的清晰性是相對的, 所以, 在已經非常清晰的語句中沒有必要再留空格, 如果語句已足夠清晰則括號內側(即左括號后面和右括號前面)不需要加空格, 多重括號間不必加空格, 因為在C/C++語言中括號已經是最清晰的標志了。
(2)在長語句中, 如果需要加的空格非常多, 那么應該保持整體清晰, 而在局部不加空格。給操作符留空格時不要連續留兩個以上空格。
2、代碼注釋
2.1 一般情況下, 源程序有效注釋量必須在20%以上。(說明: 注釋的原則是有助于對程序的閱讀理解, 在該加的地方都加了, 注釋不宜太多也不能太少, 注釋語言必須準確、易懂、簡潔。)
2.2 說明性文件(如頭文件.h 文件、.inc 文件、.def 文件、編譯說明文件.cfg 等)頭部應進行注釋, 注釋必須列出: 版權說明、版本號、生成日期、作者、內容、功能、與其它文件的關系、修改日志等, 頭文件的注釋中還應有函數功能簡要說明。
2.3 源文件頭部應進行注釋, 列出: 版權說明、版本號、生成日期、作者、模塊目的/功能、主要函數及其功能、修改日志等。
2.4 函數頭部應進行注釋, 列出: 函數的目的/ 功能、輸入參數、輸出參數、返回值、調用關系(函數、表)等
示例: 下面這段函數的注釋比較標準, 當然, 并不局限于此格式, 但上述信息建議要包含在內。
Function: // 函數名稱
Description: // 函數功能、性能等的描述
Calls: // 被本函數調用的函數清單
Called By: // 調用本函數的函數清單
Table Accessed: // 被訪問的表(此項僅對于牽扯到數據庫操作的程序)
Table Updated: // 被修改的表(此項僅對于牽扯到數據庫操作的程序)
Input: // 輸入參數說明, 包括每個參數的作用、取值說明及參數間關系
Output: // 對輸出參數的說明
Return: // 函數返回值的說明
2.5 邊寫代碼邊注釋, 修改代碼同時修改相應的注釋, 以保證注釋與代碼的一致性。不再有用的注釋要刪除。
2.6 注釋的內容要清楚、明了, 含義準確, 防止注釋二義性。
2.7 避免在注釋中使用縮寫, 特別是非常用縮寫
2.8 注釋應與其描述的代碼相近, 對代碼的注釋應放在其上方或右方(對單條語句的注釋)相鄰位置, 不可放在下面, 如放于上方則需與其上面的代碼用空行隔開。
2.9 對于所有有物理含義的變量、常量, 如果其命名不是充分自注釋的, 在聲明時都必須加以注釋, 說明其物理含義。變量、常量、宏的注釋應放在其上方相鄰位置或右方。
2.10 數組、結構、類、枚舉等) , 如果其命名不是充分自注釋的, 必須加以注釋。對數據結構的注釋應放在其上方相鄰位置, 不可放在下面; 對結構中的每個域的注釋放在此域的右方。
2.11 全局變量要有較詳細的注釋, 包括對其功能、取值范圍、哪些函數或過程存取它以及存取時注意事項等的說明。
2.12 注釋與所描述內容進行同樣的縮排。
2.13 將注釋與其上面的代碼用空行隔開。
2.14 函數的頭部應進行注釋,列出函數的功能、目的、輸入輸出參數、返回值、調用關系(表、函數)等
2.15 對變量的定義和分支語句(條件分支、循環語句等)必須編寫注釋。
2.16 對于switch語句下的case語句, 如果因為特殊情況需要處理完一個case后進入下一個case處理, 必須在該case語句處理完、下一個case語句前加上明確的注釋。
3、標識(zhi)符命名
3.1 標識符的命名要清晰、明了, 有明確含義, 同時使用完整的單詞或大家基本可以理解的縮寫, 避免使人產生誤解。(說明: 較短的單詞可通過去掉“元音”形成縮寫; 較長的單詞可取單詞的頭幾個字母形成縮寫; 一些單詞有大家公認的縮寫。)
示例: 如下單詞的縮寫能夠被大家基本認可。
temp可縮寫為 tmp; 臨時
flag可縮寫為 flg; 標志
statistic可縮寫為 stat ; 統計
increment可縮寫為 inc; 增量
message可縮寫為 msg; 消息
3.2 命名中若使用特殊約定或縮寫, 則要有注釋說明。(說明: 應該在源文件的開始之處, 對文件中所使用的縮寫或約定, 特別是特殊的縮寫, 進行必要的注釋說明。)
3.3 自己特有的命名風格, 要自始至終保持一致, 不可來回變化。(說明: 個人的命名風格, 在符合所在項目組或產品組的命名規則的前提下, 才可使用。即命名規則中沒有規定到的地方才可有個人命名風格。)
3.4 對于變量命名, 禁止取單個字符(如i、j、k… ), 建議除了要有具體含義外, 還能表明其變量類型、數據類型等, 但i、j、k 作局部循環變量是允許的。
說明: 變量, 尤其是局部變量, 如果用單個字符表示, 很容易敲錯(如i寫成j), 而編譯時又檢查不出來, 有可能為了這個小小的錯誤而花費大量的查錯時間。
3.5 命名規范必須與所使用的系統風格保持一致, 并在同一項目中統一, 比如采用UNIX的全小寫加下劃線的風格或大小寫混排的方式, 不要使用大小寫與下劃線混排的方式, 用作特殊標識如標識成員變量或全局變量的m_ 和g_ , 其后加上大小寫混排的方式是允許的
4、代碼可讀性
4.1 注意運算符的優先級,并用括號明確表達式的操作順序,避免使用默認優先級。
4.2 避免使用不易理解的數字, 用有意義的標識來替代。涉及物理狀態或者含有物理意義的常量, 不應直接使用數字, 必須用有意義的枚舉或宏來代替。
5、變量、結構
5.1 去掉沒必要的公共變量。
說明: 公共變量是增大模塊間耦合的原因之一, 故應減少沒必要的公共變量以降低模塊間的耦合度。
5.2 仔細定義并明確公共變量的含義、作用、取值范圍及公共變量間的關系。
說明: 在對變量聲明的同時, 應對其含義、作用及取值范圍進行注釋說明, 同時若有必要還應說明與其它變量的關系。
5.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, 故此變量將引起函數間較大的耦合, 并可能增加代碼測試、維護的難度。
5.4 當向公共變量傳遞數據時, 要十分小心, 防止賦與不合理的值或越界等現象發生。
說明: 對公共變量賦值時, 若有必要應進行合法性檢查, 以提高代碼的可靠性、穩定性。
5.5 防止局部變量與公共變量同名。
說明: 若使用了較好的命名規則, 那么此問題可自動消除。
5.6 嚴禁使用未經初始化的變量作為右值。
說明: 特別是在C/C++中引用未經賦值的指針, 經常會引起系統崩潰。
6、函數、過程
6.1 對所調用函數的錯誤返回碼要仔細、全面地處理
6.2 明確函數功能, 精確(而不是近似)地實現函數設計
6.3 編寫可重入函數時, 應注意局部變量的使用(如編寫C/C++ 語言的可重入函數時, 應使用auto 即缺省態局部變量或寄存器變量)
說明: 編寫C/C++語言的可重入函數時, 不應使用static局部變量, 否則必須經過特殊處理, 才能使函數具有可重入性。
6.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;
}
6.5 在同一項目組應明確規定對接口函數參數的合法性檢查應由函數的調用者負責還是由接口函數本身負責, 缺省是由函數調用者負責
說明: 對于模塊間接口函數的參數的合法性檢查這一問題, 往往有兩個極端現象, 即: 要么是調用者和被調用者對參數均不作合法性檢查, 結果就遺漏了合法性檢查這一必要的處理過程, 造成問題隱患; 要么就是調用者和被調用者均對參數進行合法性檢查, 這種情況雖不會造成問題, 但產生了冗余代碼, 降低了效率。
7、程序效率
7.1 編程時要經常注意代碼的效率
7.2 在保證軟件系統的正確性、可讀性、穩定性及可測試性的前提下,提高代碼效率
7.3 對模塊中函數的劃分及組織方式進行分析、優化, 改進模塊中函數的組織結構, 提高程序效率
7.4 編程時, 要隨時留心代碼效率; 優化代碼時, 要考慮周全
7.5 不應花過多的時間拼命地提高調用不很頻繁的函數代碼效率
7.6 要仔細地構造或直接用匯編編寫調用頻繁或性能要求極高的函數
7.7 在保證程序質量的前提下, 通過壓縮代碼量、去掉不必要代碼以及減少不必要的局部和全局變量, 來提高空間效率
7.8 在多重循環中, 應將最忙的循環放在最內層
7.9 盡量減少循環嵌套層次
7.10 避免循環體內含判斷語句, 應將循環語句置于判斷語句的代碼塊之中
7.11 盡量用乘法或其他的方法代替除法,特別是浮點運算中的除法
7.12 不要一味追求緊湊的代碼
最后提醒一句,“任何一個傻瓜都能寫出計算機可以理解的代碼,唯有寫出人類容易理解的代碼,才是優秀的程序員。” 制定一個符合自己公司情況的開發規范是很簡單的,重要的是我們能夠認識到規范的重要性,并堅持規范的開發習慣。
審核編輯 :李倩
-
華為
+關注
關注
216文章
34499瀏覽量
252350 -
編程
+關注
關注
88文章
3633瀏覽量
93853 -
C++
+關注
關注
22文章
2113瀏覽量
73742
原文標題:華為C/C++編碼規范流出
文章出處:【微信號:技術讓夢想更偉大,微信公眾號:技術讓夢想更偉大】歡迎添加關注!文章轉載請注明出處。
發布評論請先 登錄
相關推薦
評論