編碼規(guī)范,沒(méi)有最好,只有最合適,有但不執(zhí)行不如沒(méi)有。
一、編碼原則
01
可讀性
清晰第一
清晰性是易于維護(hù)程序必須具備的特征。維護(hù)期變更代碼的成本遠(yuǎn)遠(yuǎn)大于開(kāi)發(fā)期,編寫(xiě)程序應(yīng)該以人為本,計(jì)算機(jī)第二。一般情況下,代碼的可閱讀性高于性能,只有定性能是瓶頸時(shí),才應(yīng)該主動(dòng)優(yōu)化。
簡(jiǎn)潔為美
簡(jiǎn)潔就是易于理解并且易于實(shí)現(xiàn)。代碼越長(zhǎng)越難以看懂,也就越容易在修改時(shí)引入錯(cuò)誤。提倡通過(guò)簡(jiǎn)潔明了的代碼來(lái)提升代碼可靠性。廢棄的代碼要及時(shí)清除,重復(fù)代碼應(yīng)該盡可能提煉成函數(shù)。
風(fēng)格一致
所有人共同分享同一種風(fēng)格,為后期維護(hù),和代碼交接帶來(lái)便捷。
02
設(shè)計(jì)原則
- 開(kāi)放封閉原則對(duì)于擴(kuò)展是開(kāi)放的,對(duì)于修改是封閉的。
- 單一職責(zé)原則每一個(gè)子函數(shù)或者類似的代碼塊應(yīng)該只有一個(gè)職責(zé),所以只有一個(gè)原因會(huì)使其改變。
- 接口隔離原則接口盡量細(xì)化,同時(shí)接口中的方法盡量少。
- 最少知道原則一個(gè)子模塊應(yīng)該與其它模塊保持最少的了解。
- 依賴倒置原則高層模塊,低層模塊,細(xì)節(jié)(實(shí)現(xiàn))都應(yīng)該依賴抽象(即接口)。
二、編碼規(guī)范
01
文件頭申明
新增.c必須添加注釋,標(biāo)注公司名稱、文件功能說(shuō)明,創(chuàng)建日期、作者,后續(xù)修改說(shuō)明范例如下:
可配置Source Insight 自動(dòng)生成模板。
02
文件
所有.h頭文件必須采取阻止內(nèi)容被包含多于一次的機(jī)制。
- 頭文件對(duì)外接口,應(yīng)放置對(duì)外部的聲明,如對(duì)外提供的函數(shù)聲明、宏定義、類型定義等。
內(nèi)部使用的函數(shù)聲明不應(yīng)放在頭文件中。
內(nèi)部使用的宏、枚舉、結(jié)構(gòu)定義不應(yīng)放入頭文件中。
變量定義禁止在頭文件中,應(yīng)放在.c文件中。
模塊內(nèi)使用的全局變量,不應(yīng)通過(guò)在頭文件中聲明的方式直接暴露給外部。
頭文件中只包含接口的聲明,不含實(shí)現(xiàn)。
頭文件應(yīng)當(dāng)職責(zé)單一,頭文件過(guò)于復(fù)雜,依賴過(guò)于復(fù)雜是導(dǎo)致編譯時(shí)間過(guò)長(zhǎng)的主要原因。
每一個(gè).c文件應(yīng)有一個(gè)同名.h文件,用于聲明需要對(duì)外公開(kāi)的接口。
禁止頭文件循環(huán)依賴,禁止包含用不到的頭文件。
每個(gè).c源文件內(nèi)容片段按如下順序,文件注釋-包含頭文件-宏定義-數(shù)據(jù)結(jié)構(gòu)定義-變量定義-引用外部變量-引用外部函數(shù)-本地函數(shù)-全局函數(shù)。
03
函數(shù)
- 一個(gè)函數(shù)僅完成一件功能。
- 重復(fù)代碼應(yīng)該盡可能提煉成函數(shù)。說(shuō)明:重復(fù)代碼提煉成函數(shù)可以帶來(lái)維護(hù)成本的降低。重復(fù)代碼是不良代碼最典型的特征之一。在“代碼能用就不改”的指導(dǎo)原則之下,新需求增加帶來(lái)的代碼拷貝和修改,隨著時(shí)間的遷移,產(chǎn)品中堆砌著許多類似或者重復(fù)的代碼。
避免遞歸函數(shù)的代碼塊嵌套過(guò)深。
對(duì)函數(shù)的錯(cuò)誤返回碼要全面處理。說(shuō)明:一個(gè)函數(shù)(標(biāo)準(zhǔn)庫(kù)中的函數(shù)/第三方庫(kù)函數(shù)/用戶定義的函數(shù))能夠提供一些指示錯(cuò)誤發(fā)生的方法,可以通過(guò)使用錯(cuò)誤標(biāo)記、特殊的返回?cái)?shù)據(jù)或者其他手段,調(diào)用程序應(yīng)該在函數(shù)返回時(shí)立刻檢查錯(cuò)誤指示。
廢棄函數(shù)要及時(shí)清除。說(shuō)明:程序中的廢棄代碼不僅占用額外的空間,而且還常常影響程序的功能與性能,很可能給程序的測(cè)試、維護(hù)等造成不必要的麻煩。
函數(shù)傳入的不變參數(shù)使用const限制。
函數(shù)的參數(shù)個(gè)數(shù)不超過(guò)5個(gè),檢查輸入?yún)?shù)的有效性。說(shuō)明:函數(shù)的參數(shù)過(guò)多,會(huì)使得該函數(shù)易于受外部(其他部分的代碼)變化的影響,從而影響維護(hù)工作。函數(shù)的參數(shù)過(guò)多同時(shí)也會(huì)增大測(cè)試的工作量。函數(shù)的參數(shù)個(gè)數(shù)不要超過(guò)5個(gè),如果超過(guò)了建議拆分為不同函數(shù);函數(shù)的輸入主要有兩種:一種是參數(shù)輸入;另一種是全局變量、數(shù)據(jù)文件的輸入,即非參數(shù)輸入。函數(shù)在使用輸入?yún)?shù)之前,應(yīng)進(jìn)行有效性檢查。
源文件范圍內(nèi)聲明和定義的所有函數(shù),除非外部可見(jiàn),否則增加static關(guān)鍵字,針對(duì)單元測(cè)試的特殊情況,對(duì)這類函數(shù)盡量封裝一層再使用。
傳入?yún)?shù)表意有3種以上的禁止使用魔法數(shù),必須使用枚舉值且附帶注釋。
函數(shù)內(nèi)部要對(duì)參數(shù)的合法性進(jìn)行檢查。說(shuō)明:函數(shù)的輸入主要有兩種:一種是參數(shù)輸入;另一種是全局變量、數(shù)據(jù)文件的輸入,即非參數(shù)輸入。函數(shù)在使用輸入?yún)?shù)之前,應(yīng)進(jìn)行有效性檢查。
除打印類函數(shù)外,不要使用可變長(zhǎng)函數(shù)。說(shuō)明:可變長(zhǎng)參函數(shù)的處理過(guò)程比較復(fù)雜容易引入錯(cuò)誤,而且性能也比較低,使用過(guò)多的可變長(zhǎng)參函數(shù)將導(dǎo)致函數(shù)的維護(hù)難度大大增加。
每個(gè)函數(shù)都要返回錯(cuò)誤碼,調(diào)用程序必須在函數(shù)返回時(shí)檢查錯(cuò)誤碼。
標(biāo)識(shí)符的命名要清晰明了,有明確含義,使用完整的單詞,盡量避免名字中出現(xiàn)數(shù)字編號(hào)或特殊符號(hào)。
函數(shù)名稱需體現(xiàn)出函數(shù)具體功能,均由功能單詞拼接組成,絕不允許出現(xiàn)中文拼音。
函數(shù)命名應(yīng)以函數(shù)要執(zhí)行的動(dòng)作命名,一般采用動(dòng)詞或者動(dòng)詞+名詞的結(jié)構(gòu)。
04
變量
- 不用或者少用全局變量。說(shuō)明:?jiǎn)蝹€(gè)文件內(nèi)部可以使用static的全局變量,可以將其理解為類的私有成員變量。全局變量應(yīng)該是模塊的私有數(shù)據(jù),不能作用對(duì)外的接口使用,使用static類型定義,可以有效防止外部文件的非正常訪問(wèn)。直接使用其他模塊的私有數(shù)據(jù),將使模塊間的關(guān)系逐漸走向“剪不斷理還亂”的耦合狀態(tài),這種情形是不允許的。
避免局部變量與全局變量同名。說(shuō)明:盡管局部變量和全局變量的作用域不同而不會(huì)發(fā)生語(yǔ)法錯(cuò)誤,但容易使人誤解。
嚴(yán)禁使用未經(jīng)初始化的變量。
明確全局變量的初始化順序,避免跨模塊的初始化依賴。說(shuō)明:系統(tǒng)啟動(dòng)階段,使用全局變量前,要考慮到該全局變量在什么時(shí)候初始化,兩者之間的時(shí)序關(guān)系,誰(shuí)先誰(shuí)后,一定要分析清楚,不然后果往往是低級(jí)而又災(zāi)難性的。
數(shù)據(jù)必須對(duì)外開(kāi)放時(shí),應(yīng)封裝接口函數(shù)來(lái)讀寫(xiě),同時(shí)注意全局?jǐn)?shù)據(jù)的訪問(wèn)互斥。說(shuō)明:避免直接暴露內(nèi)部數(shù)據(jù)給外部模型使用,是防止模塊間耦合最簡(jiǎn)單有效的方法。
一個(gè)變量只有一個(gè)功能,不能把一個(gè)變量用作多種用途。說(shuō)明:一個(gè)變量只用來(lái)表示一個(gè)特定功能,不能把一個(gè)變量作多種用途,即同一變量取值不同時(shí),其代表的意義也不同。
數(shù)據(jù)結(jié)構(gòu)功能單一,不要設(shè)計(jì)面面俱到的數(shù)據(jù)結(jié)構(gòu)。說(shuō)明:相關(guān)的一組信息才是構(gòu)成一個(gè)結(jié)構(gòu)體的基礎(chǔ),結(jié)構(gòu)的定義應(yīng)該可以明確的描述一個(gè)對(duì)象,而不是一組相關(guān)性不強(qiáng)的數(shù)據(jù)的集合。設(shè)計(jì)結(jié)構(gòu)時(shí)應(yīng)力爭(zhēng)使結(jié)構(gòu)代表一種現(xiàn)實(shí)事務(wù)的抽象,而不是同時(shí)代表多種。結(jié)構(gòu)中的各元素應(yīng)代表同一事務(wù)的不同側(cè)面,而不應(yīng)把描述沒(méi)有關(guān)系或關(guān)系很弱的不同事務(wù)的元素放到同一結(jié)構(gòu)體中。
盡量減少?zèng)]有必要的數(shù)據(jù)類型默認(rèn)轉(zhuǎn)換與強(qiáng)制轉(zhuǎn)換。說(shuō)明:當(dāng)進(jìn)行數(shù)據(jù)類型強(qiáng)制轉(zhuǎn)換時(shí),其數(shù)據(jù)的意義、轉(zhuǎn)換后的取值等都有可能發(fā)生變化,而這些細(xì)節(jié)若考慮不周,就很有可能留下隱患。
示例:如下賦值,多數(shù)編譯器不產(chǎn)生告警,但值的含義有變化。
確認(rèn)未使用的變量應(yīng)當(dāng)刪除。對(duì)于變量自增 ++ 和自減--,禁止在宏定義中使用,禁止和其他語(yǔ)句復(fù)合,因拆分單獨(dú)執(zhí)行。示例:if(++i>10) 錯(cuò)誤寫(xiě)法,必須改為i++;if(i>10)
05
宏和常量
宏定義和常量使用大寫(xiě)字母或下劃線。
用宏定義表達(dá)式時(shí),要使用完備的括號(hào),如下:
宏定義中盡量不要使用return、goto、continue、break等改變程序流程的語(yǔ)句。
常量建議使用const定義代替宏,如下:
除非必要,應(yīng)盡可能使用函數(shù)代替宏 。
將宏定義的多條表達(dá)式放在大括號(hào)中。
使用宏時(shí),不允許參數(shù)發(fā)生變化。
盡量少用魔法數(shù),或者必須加注釋說(shuō)明,或者修改方案,如內(nèi)存長(zhǎng)度操作禁止使用常數(shù),非特殊情況必須使用sizeof自動(dòng)處理。
06
命名
命名采用unix like風(fēng)格,單詞用小寫(xiě)字母,每個(gè)單詞之間用下劃線分割,引用的第三方的代碼可保持原有風(fēng)格,命名盡量使用通用英文單詞或縮寫(xiě)。
文件:
文件名命名可根據(jù)平臺(tái)自有規(guī)則命名,一般采用小寫(xiě)字符,字段之間使用下劃線分隔;相同功能的 .c和.h文件名相同。
枚舉:
枚舉定義:宏定義和枚舉值禁止使用小寫(xiě)字母,不能以下劃線開(kāi)頭,字段之間使用下劃線分隔,若邏輯中要標(biāo)注多種狀態(tài),狀態(tài)不允許用數(shù)字表示。
結(jié)構(gòu)體:
結(jié)構(gòu)體定義,若同一功能所使用到的參數(shù),盡量用結(jié)構(gòu)體來(lái)定義表示,便于相關(guān)參數(shù)獲取和設(shè)置。
純業(yè)務(wù)邏輯代碼,與平臺(tái)無(wú)關(guān)的,必須使用小寫(xiě)字符和下劃線分隔。
函數(shù)函數(shù)名定義:
函數(shù)名稱需體現(xiàn)出函數(shù)具體功能,均由功能單詞拼接組成,使用小寫(xiě)字母和下劃線拼接,其中全局函數(shù)必須以xx_為前綴,在.h里面申明全局函數(shù),補(bǔ)充完整注釋;局部函數(shù)使用static限制。
變量:
禁止使用全大寫(xiě)字母命名變量,全局變量至少5個(gè)字母,使用高頻次的全局變量盡量簡(jiǎn)短。
全局變量命名表達(dá)其作用,且以小寫(xiě)字母g_開(kāi)頭,后面拼接功能英文,如地址:g_addr。
變量名的拼接,全部使用小寫(xiě)字母和下劃線拼接,函數(shù)內(nèi)局部變量允許使用單個(gè)字母。
多個(gè)同類的變量封裝成結(jié)構(gòu)體。
推薦命名:
07
注釋
注釋?xiě)?yīng)放在其代碼上方相鄰位置或右方,不可放在下面。
注釋的內(nèi)容要清楚明了,防止注釋二義性。
修改代碼時(shí)同步更新注釋,保證注釋與代碼的一致性。
函數(shù)聲明處注釋描述函數(shù)功能、性能及用法,提供參考范本如下:
全局變量要有較詳細(xì)的注釋:
函數(shù)內(nèi)部不是注釋越多越好,而是變量命名和邏輯清晰,自注釋最好,特殊情況或者需要特別注意的地方才加注釋,并且注釋要放在代碼行的上方。
基于SDK開(kāi)發(fā),在基線工程上改動(dòng)代碼,不允許刪除源代碼,修改代碼必須增加注釋,必須使用關(guān)鍵字“XX_CODE”標(biāo)注修改原因,方便后續(xù)打補(bǔ)丁,范例如下:
對(duì)于非c源碼的文件,在這個(gè)注釋格式的基礎(chǔ)上,每行添加對(duì)應(yīng)的注釋符號(hào)。
修改與外設(shè)驅(qū)動(dòng)、通信協(xié)議、系統(tǒng)底層等相關(guān)的代碼,具有特殊隱含限制的代碼,必須提交詳細(xì)的修改原因,便于后續(xù)版本回溯查找原因。
復(fù)雜且相對(duì)獨(dú)立的功能,單獨(dú)使用markdown文檔說(shuō)明開(kāi)發(fā)方案、實(shí)現(xiàn)技術(shù)、應(yīng)用場(chǎng)景、使用限制等,隨代碼提交。
08
排版與格式
程序塊采用縮進(jìn)風(fēng)格編寫(xiě),每級(jí)縮進(jìn)為4個(gè)空格。
相對(duì)獨(dú)立的程序塊之間、變量說(shuō)明之后必須加空行。
多個(gè)短語(yǔ)句不允許寫(xiě)在同一行內(nèi),長(zhǎng)語(yǔ)句不能拆分需要分行寫(xiě)。
if、for、do、while、case、switch、default等語(yǔ)句獨(dú)占一行,{換行且獨(dú)占一行。
賦值語(yǔ)句不要寫(xiě)在if等語(yǔ)句中,或者作為函數(shù)的參數(shù)使用。
邏輯表達(dá)式每個(gè)子項(xiàng)都使用()。
if與else if/else必須以’{}’分隔,且 ‘{’與‘}’各占一行,if-else分3層以上必須以else子句結(jié)束,即使操作為空,并增加注釋://do nothing
switch語(yǔ)句必須有default分支。
在兩個(gè)以上的關(guān)鍵字、變量、常量進(jìn)行對(duì)等操作時(shí),它們之間的操作符之前、之后或者前后要加空格;進(jìn)行非對(duì)等操作時(shí)(如->),后面不應(yīng)加空格。
文件編寫(xiě)完成后,統(tǒng)一使用Astyle自動(dòng)格式化工具整理一遍再提交到版本庫(kù)。
三、編碼要求
01
安全性
對(duì)用戶輸入數(shù)值進(jìn)行有效范圍檢查。
對(duì)輸入?yún)?shù)進(jìn)行邊界判斷,尤其對(duì)指針變量。
嚴(yán)禁使用未經(jīng)初始化的變量作為右值,所有變量都要初始化。
每個(gè)普通變量(整型、字符型)的定義都要考慮范圍,嚴(yán)防溢出。
每個(gè)數(shù)組的定義和使用都要嚴(yán)防越界的發(fā)生。
要盡量避免隱式或者顯式的類型轉(zhuǎn)換,防止截?cái)嗟陌l(fā)生或者符號(hào)的丟失。
動(dòng)態(tài)申請(qǐng)的內(nèi)存盡量在本函數(shù)內(nèi)釋放,特殊情況下,必須補(bǔ)充注釋提醒外界釋放內(nèi)存。
02
可移植性
不能定義、重定義或取消定義標(biāo)準(zhǔn)庫(kù)/平臺(tái)中保留的標(biāo)識(shí)符、宏和函數(shù)。
提取與平臺(tái)有關(guān)的通用函數(shù),封裝后統(tǒng)一放在固定文件,方便后期替換升級(jí)。
源文件必須使用原有平臺(tái)、SDK一致的文件編碼(GB2312/UTF8),有效代碼中不得出現(xiàn)中文字符。
通用功能使用功能宏控制,且代碼集中。
使用系統(tǒng)接口,尤其是不同平臺(tái)API不同的,使用函數(shù)名中帶pal的接口封裝并注釋,便于后續(xù)移植到其他平臺(tái)。
引用第三方開(kāi)源代碼,允許保留其原始風(fēng)格,客制化修改必須補(bǔ)充完整注釋。
四、規(guī)范實(shí)施
編碼規(guī)范是軟件開(kāi)發(fā)團(tuán)隊(duì)合作的標(biāo)準(zhǔn),但實(shí)際開(kāi)發(fā)過(guò)程中存在各種不可控因素,尤其是項(xiàng)目進(jìn)度壓力和開(kāi)發(fā)者水平與認(rèn)知的差異,導(dǎo)致軟件規(guī)則不能嚴(yán)格執(zhí)行。隨著軟件工程規(guī)模的擴(kuò)大,軟件交期、代碼同步、重構(gòu)或交接,其風(fēng)險(xiǎn)也逐漸放大。因此,存在合適的編碼規(guī)則并不能解決問(wèn)題,只有強(qiáng)制代碼格式化,才能真正落實(shí)編碼規(guī)范統(tǒng)一。
軟件質(zhì)量是項(xiàng)目成敗的關(guān)鍵點(diǎn)之一,在開(kāi)發(fā)周期有限,人力資源不足的情況下,使用工具實(shí)現(xiàn)代碼自動(dòng)掃描,分析出潛在隱患點(diǎn),從源頭減少軟件bug,是軟件如期交付的重要保證。實(shí)現(xiàn)代碼自動(dòng)格式化和靜態(tài)分析,可以有效規(guī)避軟件風(fēng)險(xiǎn)。
-
C語(yǔ)言
+關(guān)注
關(guān)注
180文章
7595瀏覽量
135871 -
編碼
+關(guān)注
關(guān)注
6文章
933瀏覽量
54731 -
函數(shù)
+關(guān)注
關(guān)注
3文章
4284瀏覽量
62325
發(fā)布評(píng)論請(qǐng)先 登錄
相關(guān)推薦
評(píng)論