目錄
前言
一、編程規范的作用
二、規范的三種形式
三、規范的內容
1. 基本原則
原則1-1
原則1-2
原則1-3
原則1-4
原則1-5
原則1-6
原則1-7
2. 布局
規則2-1-1
規則2-1-2
規則2-1-3
規則2-1-4
規則2-1-5
規則2-1-6
規則2-2-1
規則2-2-2
規則2-2-3
建議2-3-1
規則2-4-1
規則2-4-2
規則2-4-3
規則2-4-4
規則2-4-2
規則2-4-6
規則2-5-1
3. 注釋
規則3-1
規則3-2
規則3-3
?編輯
規則3-4
4. 命名規則
規則4-1
規則4-2
規則4-3
規則4-4
規則4-5
規則4-6
規則4-7
規則4-8
規則4-9
規則4-10
規則4-11
建議4-12
建議4-13
5. 變量、常量與類型
規則5-1
規則5-2
建議5-3
6. 表達式與語句
規則6-1
規則6-2
規則6-3
規則6-4
規則6-5????????
?編輯
規則6-6
?編輯
規則6-7
規則6-8
規則6-9
建議6-10
7. 函數與過程
規則7-1
規則7-2
規則7-3
規則7-4
規則7-5
建議7-6
建議7-7
建議7-8
建議7-9
8. 可靠性
規則8-1
規則8-2
規則8-3
規則8-4
規則8-5
規則8-6
規則8-7
規則8-8
建議8-9
9. 可測試性
規則9-1
規則9-2
規則9-3
10.斷言與錯誤外理
規則10-1
規則10-2
規則10-3
前言
編碼規范是成為一個優質程序員的重要一課,它是編程的樣式的模板。
為了跟大佬們一樣寫出簡潔、可維護、可靠、可測試、高效、可移植的代碼,我參考網上的資料做了一個歸類。
一、編程規范的作用
1.提高源程序的可讀性和可維護性
2.降低錯誤的機會
3.提高源代碼可重用性和質量
二、規范的三種形式
1.原則:編程時應該堅持的指導思想
2.規則:編程時必須遵守的約定
3.建議: 編程時必須加以考慮的約定
三、規范的內容
1. 基本原則
原則1-1
首先是為人編寫程序,其次才是計算機。
說明:這是軟件開發的基本要點,軟件的生命周期貫穿產品的開發、測試、生產、用戶使用、版本升級和后期維護等長期過程,只有易讀、易維護的軟件代碼才具有生命力。
原則1-2
保持代碼的簡明清晰,避免過分的編程技巧。
簡單是最美。保持代碼的簡單化是軟件工程化的基本要求。不要過分追求技巧,否則會降低程序的可讀性。
原則1-3
所有的代碼盡量遵循ANSI C標準
所有的代碼盡可能遵循ANSI C標準,盡可能不使用ANSI C未定義的或編譯器擴展的功能。
原則1-4
編程時首先達到正確性,其次考慮效率。
編程首先考慮的是滿足正確性、健壯性、可維護性、可移植性等質量因素,最后才考慮程序的效率和資源占用。
原則1-5
避免或少用全局變量
過多地使用全局變量,會導致模塊間的緊耦合違反模塊化的要求
原則1-6
盡量遙免使用GOTO語句
原則1-7
盡可能復用、修正老的代碼。
盡量選擇可借用的代碼,對其修改優化以達到自身要求。
2. 布局
規則2-1-1
遵循統一的布局順序來書寫頭文件#ifmndef 文件名 H(全大寫)
#defie
文件名 H
其它條件編譯選項
#include(依次為標準庫頭文件、非標準庫頭文件)常量定義
全局宏
全局數據類型
類定義
模板 (template)(包括C++中的類模板和函數模板) 全局函數原型
#endif
規則2-1-2
遵循統一的布局順序來書寫實現文件
文件頭注釋
#include(依次為標準庫頭文件、非標準庫頭文件)常量定義
文件內部使用的宏
文件內部使用的數據類型
全局變量
本地變量(即靜態全局變量)
局部函數原型
類的實現全局函數局部函數
規則2-1-3
使用注釋塊分離上面定義的節
規則2-1-4
頭文件必須要避免重復包含
規則2-1-5
包含標準庫頭文件用尖括號 < >
包含非標準庫頭文件用雙引號 " "
規則2-1-6
遵循統一的順序書寫類的定義及實現
類的定義(在定義文件中) 按如下順序書寫:
- 公有屬性,公有函數
- 保護屬性,保護函數
- 私有屬性,私有函數
類的實現(在實現文件中) 按如下順序書寫:
- 構造函數,析構函數
- 公有函數
- 保護函數
- 私有函數
規則2-2-1
程序中一行的代碼和注釋不能超過80列
包括空格在內不超過80列
規則2-2-2
if、 else、 else if、 for、while、do等語句自占一行,執行語句不得緊跟其后。不論執行語句有多少都要加{ }
規則2-2-3
結構型的數組、多維的數組如果在定義時初始化,按照數組的矩陣結構分行書寫。
建議2-3-1
在switch語句中,每一個case分支和default要用{ }括起來,{ }中的內容需要縮進。
規則2-4-1
不同邏輯程序塊之間要使用空行分隔
規則2-4-2
多元運算符和它們的操作數之間至少需要一個空格。
規則2-4-3
關鍵字之后要留空格
if、for、while等關鍵字之后應留一個空格再跟左括號 ’(’,以突出關鍵字
另外 sizeof 是關鍵字,strlen 是函數
規則2-4-4
函數名之后不要留空格
函數名后緊跟左括號 ’(’,以與關鍵字區別
規則2-4-2
不是行結束符號時其后要留空格
規則2-4-6
注釋符與注釋內容之間要用一個空格進行分隔
規則2-5-1
函數聲明時,類型與名稱不允許分行書寫
3. 注釋
規則3-1
文件頭部必須進行注釋,包括:.h文件、.c文件、.cpp文件、.inc文件、.def文件、編譯說明文件.cfg等。
注釋必須列出:版權信息、文件標識、內容摘要、版本號、作者、完成日期、修改信息等
規則3-2
函數頭部應進行注釋,列出:函數的目的/功能、輸入參數、輸出參數、返回值、訪問和修改的表、修改信息等。
說明:注釋必須列出:函數名稱、功能描述、輸入參數、輸出參數、返回值、修改信息等
規則3-3
包含在中代碼塊的結束處應加注釋,便于閱讀。
特別是多分支、多重嵌套的條件語句或循環語句。
規則3-4
注釋應與其描述的代碼相近,對代碼的注釋應放在其上方或右方(對單條語句的注釋) 相鄰位置不可放在下面,如放于上方則需與其上面的代碼用空行隔開
4. 命名規則
規則4-1
標識符要采用英文單詞或其組合,便于記憶和閱讀,切總使用漢語拼音來命名。
標識符應當直觀且可以拼讀,可望文知義,避免使人產生誤解。程序中的英文單詞一般不要太復雜,用詞應當準確。
規則4-2
標識符的命名應當符合“min-lengt && max-information”原則
較短的單詞可通過去掉“元音”形成縮寫,較長的單詞可取單詞的頭幾個字母形成縮寫,一些單詞有大家公認的縮寫,常用單詞的縮寫必須統一。協議中的單詞的縮寫與協議保持一致對于某個系統使用的專用縮寫應該在某處做統一說明。
例如:
- temp 可縮寫為 tmp ;
- flag 可縮寫為 flg ;
- statistic 可縮寫為 stat ;
- increment 可縮寫為 inc ;
- message 可縮寫為 msg ;
規則4-3
用正確的反義詞組命名具有互斥意義的變量或相反動作的函數等
- add / remove;
- begin / end;
- create /?destroy;
- insert /?delete;
- first / last;
- get / release;
- increment / decrementputget;
- lock /?unlock ;
- open / close ;
- min / max;
- old /?new;
- start /?stop;
- source /?target ;
- next /?previous;
- show?/ hide;
- send /?receive ;
- source /?destination;
- cut / paste;
- up / down;
規則4-4
宏、常量名都要使用大寫字母,用下劃線 '_' 分割單詞。
預編譯宏定義使用下劃線 '_' 開始。
例如:
DISP_BUF_SIZE、MIN_VALUE、MAX_VALUE?
規則4-5
變量名長度應小于31個字符,以保持與ANSI C標準一致。
不得取單個字符(如i、j、k等)作為變量名,但是局部循環變量除外。
規則4-6
程序中局部變量不要與全局變量重名
盡管局部變量和全局變量的作用域不同而不會發生語法錯誤,但容易使人誤解。
規則4-7
使用一致的前綴來區分變量的作用域
變量活動范圍前綴規范如下:
規則4-8
使用一致的小寫類型指示符作為前綴來區分變量的類型。
規則4-9
完整的變量名應由前綴+變量名主體組成,變量名的主體應當使用“名詞”或者“形容詞 +?名詞”,且首字母必須大寫。
例如:
- float g fValue;?// 類型為浮點數的全局變量
- char *pcOldChar; // 類型為字符指針的局部變量char
規則4-10
- 結構名、聯合名、枚舉名由前綴T_開頭。
- 事件名由前綴EV 開頭
規則4-11
類名采用大小寫結合的方法。在構成類名的單詞之間不用下劃線,類名在開頭加上C,類的成員變量統一在前面加m_前綴
建議4-12
盡量避免名字中出現數字編號,如Value1、Value2等,除非邏輯上的確需要編號
建議4-13
標識符前最好不加項目、產品、部門的標識
這樣做的目的是為了代碼的可重用性
5. 變量、常量與類型
規則5-1
宏定義中如果包含表達式或變量,表達式和變量必須用小括號括起來。
宏定義中,對表達式和變量使用括號,可以避免可能發生的計算錯誤
正例:
#define HANDLE(A,B) (( A ) / ( B ))
反例:
#define HANDLE(A,B)? (A / B)
規則5-2
使用宏定義多行語句時,必須使用把這些語句括起來。
在宏定義中,對多行語句使用大括號,可以避免可能發生的錯誤。
建議5-3
結構中元素的個數應適中。
若結構中元素個數過多可考慮依據某種原則把元素組成不同的子結構,以減少原結構中元素的個數
6. 表達式與語句
規則6-1
一條語句只完成一個功能
規則6-2
在表達式中使用括號,使表達式的運算順序更清晰。
由于將運算符的優先級與結合律熟記是比較困難的,為了防止產生歧義并提高可讀性,即使不加括號時運算順序不會改變,也應當用括號確定表達式的操作順序。
規則6-3
避免表達式中的附加功能,不要編寫太復雜的復合表達式。
規則6-4
不可將布爾變量和邏輯表達式直接與TRUEFALSE或者1、0進行比較。TURE和FALSE的定義值是和語言環境相關的,且可能會被重定義的
規則6-5????????
在條件判斷語句中,當整型變量與0比較時,不可模仿布爾變量的風格,應當將整型變量用“==”或“!=”直接與0比較。
規則6-6
不可將浮點變量用“==”或“!=”上任何數字比較
規則6-7
應當將指針變量用“==”或“!=”與NULL比較
規則6-8
在switch語句中,每一個case分支必須使用break結尾,最后一個分支必須是default分支。
規則6-9
不可在for 循環體內修改循環變量防止for 循環失去控制。
建議6-10
循環嵌套次數不大于3次
7. 函數與過程
規則7-1
如果函數沒有參數,則用void填充
規則7-2
如果參數是指針,且僅作輸入用,則應在類型前加const。
防止該指針在函數體內被意外修改
例如:
int GetStrLen(const char *pcString):
規則7-3
不要省略返回值的類型,如果函數沒有返回值,那么應聲明為void類型
- C語言中,凡不加類型說明的函數,一律自動按整型處理。如果不注明類型,容易被誤解為void類型,產生不必要的麻煩
- C++語言有很嚴格的類型安全檢查,不允許上述情況發生。由于C++程序可以調用C函數,為了避免混亂,規定任何C/ C++函數都必須有類型。
規則7-4
對于有返回值的函數,每一個分支都必須有返回值。
為了保證對被調用函數返回值的判斷,有返回值的函數中的每一個退出點都需要有返回值。
規則7-5
防止將函數的參數作為工作變量
將函數的參數作為工作變量,有可能錯誤地改變參數內容,所以很危險。對必須改變的參數最好先用局部變量代之,最后再將該局部變量的內容賦給該參數。
建議7-6
如果返回值表示函數運行是否正常規定0為正常退出,不同非0值標識不同異常退出。避免使用TRUE或FALSE作為返回值
建議7-7
函數體的規模不能太大,盡量控制在200行代碼之內
建議7-8
減少函數本身或函數間的遞歸調用
遞歸調用特別是函數間的遞歸調用 (如A->B->C->A),影響程序的可理解性,遞歸調用一般都占用較多的系統資源(如棧空間) ;遞歸調用對程序的測試有一定影響。故除非為某些算法或功能的實現方便,應減少沒必要的遞歸調用。
對于前臺軟件為了系統的穩定性和可靠性,往往規定了進程的堆棧大小。如果采用了遞歸算法,收斂的條件又往往難以確定,很容易使得進程的堆棧溢出,破壞系統的正常運行:另外,由于無法確定遞歸的次數,降低了系統的穩定性和可靠性。
建議7-9
設計高扇入、合理扇出的函數
扇出是指一個函數直接調用(控制) 其它函數的數目,而扇入是指有多少上級函數調用它。
扇出過大,表明函數過分復雜,需要控制和協調過多的下級函數:而扇出過小,如總是1,表明函數的調用層次可能過多,這樣不利于程序閱讀和函數結構的分析,并且程序運行時會對系統資源如堆棧空間等造成壓力。函數較合理的扇出(調度函數除外) 通常是3-5。扇出太大,一般是由于缺乏中間層次,可適當增加中間層次的函數。扇出太小,可把下級函數進步分解成多個函數,或合并到上級函數中。當然分解或合并函數時,不能改變要實現的功能,也不能違背函數間的獨立性。
扇入越大,表明使用此函數的上級函數越多,這樣的函數使用效率高,但不能違背函數間的獨立性而單純地追求高扇入。公共模塊中的函數及底層函數應該有較高的扇入。
8. 可靠性
規則8-1
在程序編制之前,必須了解編譯系統的內存分配方式,特別是編譯系統對不同類型的變量的內存分配規則,如局部變量在何處分配、靜態變量在何處分配等。
規則8-2
防止內存操作越界
內存操作主要是指對數組、指針、內存地址等的操作,內存操作越界是軟件系統主要錯誤之一,后果往往非常嚴重,所以當我們進行這些操作時一定要仔細。
規則8-3
必須對動態申請的內存做有效性檢查,并進行初始化;動態內存的釋放必須和分配成對以防止內存泄漏,釋放后內存指針置為NULL。
- 對嵌入式系統,通常內存是有限的,內存的申請可能會失敗,如果不檢查就對該指針進行操作,可能出現異常,而且這種異常不是每次都出現比較難定位。
- 指針釋放后,該指針可能還是指向原有的內存塊,可能不是,變成個野指針,一般用戶不會對它再操作,但用戶失誤情況下對它的操作可能導致程序崩潰。
規則8-4
不使用realloc()。
調用realloc對一個內存塊進行擴展,導致原來的內容發生了存儲位置的變化, realloc函數既要調用free,又要調用malloc。執行時究竟調用哪個函數,取決于是要縮小還是擴大相應內存塊的大小
規則8-5
變量在使用前應初始化,防止未經初始化的變量被引用。
不同的編譯系統,定義的變量在初始化前其值是不確定的。有些系統會初始化為0,而有些不是
規則8-6
指針類型變量必須初始化為NULL
規則8-7
指針不要進行復雜的邏輯或算術操作。
指針加一的偏移,通常由指針的類型確定,如果通過復雜的邏輯或算術操作,則指針的位置就很難確定
規則8-8
如果指針類型明確不會改變,應該強制為const類型的指針,以加強編譯器的檢查
可以防止不必要的類型轉換錯誤。
建議8-9
C++程序中,分配內存使用new和delete,而不使用malloc和free。
new和delete操作由編譯器決定具體分配和釋放內存的大小,相對于malloc和firee更為高級
9. 可測試性
規則9-1
在同一項目組或產品組內,為準備集成測試和系統聯調,要有一套統一的調測開關及相應信息輸出函數,并且要有詳細的說明統一的調試接口和輸出函數由模塊設計和測試人員根據項目特性統一制訂,由項目系統人員統一納入系統設計中
規則9-2
在同一個項目組或產品組內,調測打印出的信息串要有統一的格式。信息串中應當包含所在的模塊名(或源文件名) 及行號等信息。
規則9-3
在編寫代碼之前,應預先設計好程序調試與測試的方法和手段,并設計好各種調測開關及相應測試代碼(如打印函數等)
程序的調試與測試是軟件生存周期中非常重要的一個階段,如何對軟件進行較全面、高效率的測試并盡可能地找出軟件中的錯誤就成為非常關鍵的問題。因此在編寫源代碼之前,除了要有一套比較完善的測試計劃外,還應設計出一系列測試代碼作為手段,為單元測試、集成測試及系統聯調提供方便
10.斷言與錯誤外理
規則10-1
整個軟件系統應該采用統一的斷言。如果系統不提供斷言,則應該自己構造一個統一的斷言供編程時使用。
規則10-2
指向指針的指針及更多級的指針必須逐級檢查
規則10-3
正式軟件產品中應把斷言及其它調測代碼去掉 (即把有關的調測開關關掉 ) ,加快軟件運行速度。