有人說過:“程式源代碼其實是跟人閱讀的,隻是恰好機器可以編譯而已”。程式設計初學者常常會有這樣一個觀念,就是我的程式隻要編譯通過了,運作沒有問題那就萬事大吉了。至于代碼的編寫規不規範,完全就是無關緊要的小事情。如果是處于學習階段,比如為了完成在學校的C語言課的作業,那麼花心思在代碼規範上的确沒有特别的必要,因為這些代碼基本不會進入實用工程,也不會被很多人閱讀到。
但是,如果應用到了工程領域,比如在軟體/網際網路企業的技術研發部門,或者Github等平台上的開源工程,那麼程式設計的規範性将變得無比重要。因為在這些場合,你寫的代碼将被許多人閱讀,并且可能會成為許多人進行後續開發的基礎。此時,差勁的代碼風格将嚴重拉低其他開發人員的工作效率。是以,我們推薦從一開始學習便養成一個良好的程式設計習慣,維持一個合理的代碼風格,這樣對未來的工作大有裨益。
C語言程式設計風格的内容相當龐大,這裡隻挑選一部分相對常用而且比較重要的内容作為參考,主要分為5個部分,包括排版、注釋、命名、變量/結構、函數等。
程式排版使得代碼的結構更加清晰明了,而且有助于了解上下文的邏輯關系。
(1)程式塊應根據上下文關系采用縮進風格,縮進的長度根據具體标準規定;
(2)獨立的程式塊之間、變量說明之後必須加空行;比如:
(3)一條語句占一行,不允許将兩條語句寫在一行中;
(4)對于存在判斷、循環的代碼,像if/for/do/while/case/swith/default等部分獨占一行,且無論執行部分有多少條語句,都必須使用大括号{ };
(5)包裹代碼塊的大括号{ }必須另起一行,不要跟随上一行代碼的末尾;且大括号也要符合代碼縮進規則;
注釋雖然不影響程式的運作,但仍然是代碼的重要組成部分。完善的代碼注釋對快速了解代碼的功能具有重要意義,相反如果代碼邏輯複雜且沒有注釋,或注釋不完整、不科學,那麼旁人很難了解這段代碼究竟是做什麼的。需注意一點,别人無法了解的程式即使運作良好,也永遠都是垃圾代碼。
添加注釋需要注意,注釋應簡潔、有效,有助于提升對代碼的了解。是以添加注釋應注意不要添加一些完全無意義或者錯誤的資訊。通常,我們認為一套代碼按照優劣分為4個等級:
第一等級:不需要注釋,通過優秀的代碼風格、辨別符命名和代碼的上下文關系就可以達到高可讀性的代碼;
第二等級:代碼的命名群組織規範、風格稍顯不足,但有完善的注釋;
第三等級:代碼風格和注釋都不夠完善,但是組織了較為完善的文檔在一定程度彌補了這一缺陷;
第四等級:代碼風格、注釋和文檔都不足,這種就屬于其他人難以了解的垃圾代碼。
函數頭部的注釋:
在函數頭部應添加注釋,說明函數的功能、參數、傳回值等資訊。下面的注釋格式比較完善,不一定要局限與此,但建議保留其中的大部分資訊:
代碼中的注釋:
語句的注釋應在被注釋語句的正上方或右方。如果是在上方的話,除非十分必要否則不要再代碼和注釋之間插入空格。
對于具有實體含義的常量和變量,以及資料結構,除非命名本身是充分注釋的,在聲明時必須加以注釋。
全局變量要有詳細的注釋,包括對其功能、取值範圍、使用的函數以及存取時的注意事項等。
注釋與上方的代碼用一行空格間隔。
對選擇、循環語句應當添加注釋,說明分支、循環體的意義。
在程式塊結束的大括号右方添加注釋,說明比對的程式塊開始位置。
如以下代碼:
辨別符命名是代碼風格中的重要組成部分,甚至直接決定了代碼可讀性的高低。最常用的辨別符無非就是常量名、變量/結構體名、函數名、宏定義、标簽名等。對不同的辨別符類型一般适用不同的要求,但有一些基本要求是一緻的:辨別符的命名必須清晰明了,含義明确,盡量少地使用縮寫;嚴禁使用無意義的單個字母如a, b, i, m, n或者func1, fun等無意義的單詞或縮寫用于命名;
對于變量名和函數名,通常比較常用的有兩種命名法:駝峰命名法和下劃線命名法,這兩種方法的根本差別在于通過怎樣的方式來分隔辨別符命名中的邏輯斷點。
駝峰命名法:通過大小寫字母的變化進行分隔,如:int imgWidth = 0; char *studentName = “Jerry”;
下劃線命名法:通過下劃線進行分隔,如:double earth_moon_distance;
對于函數名和變量名,一般可以使用不同的命名方法,但是需要注意的是隻要標明的命名規範就要從頭到尾保持不變。通常,我個人的習慣是,變量名和結構體名使用駝峰命名法,變量名用小寫開頭,結構體用大寫開頭;函數名使用下劃線命名法,公有API以大寫字母開頭,私有函數以小寫開頭并聲明為static類型。
另外,對于常量、結構體成員變量、全局變量,還可以參考匈牙利命名法的原則,在變量名前加入字首c_、m_和g_。
對于宏定義的命名,一律全部使用大寫字母,邏輯斷點采用下劃線分隔,如
#define MAX_ARRAY_LENGTH 256
對于頭檔案保護作用的宏定義,則以頭檔案的檔案名命名,邏輯斷點和擴充名前的點全部用下劃線替代,并且在首位各添加一個下劃線,如
通常标簽名配合goto語句一起使用。由于goto本來就是比較冷門的語句,标簽也不是很常用。如果用到,則全部使用小寫字母,并且在結尾加_label,如:
變量和結構的使用是程式設計中最為頻繁的動作,如果能正确規範變量的使用,那麼對整體的程式設計風格的提升大有幫助。
(1)變量定義之後立刻初始化。通常數值型變量定以後可以立刻初始化為0、某個負數或其他無意義的數值,指針變量定義後立刻初始化為NULL。這樣在後面使用變量時可以更友善地判斷變量是否已經被正确地處理,防止無意中使用了未經初始化的值。
(2)除非特别必要,否則盡量減少全局變量的使用,對于跨檔案使用的全局變量更要慎重。全局變量是造成代碼之間耦合的重要因素,通常使用全局變量越多,代碼就越難以維護。
(3)對于數值完全不應當改變的量,一律定義為常量,防止被誤修改。
(4)定義一個結構體的功能應當越具體越好,不應定義一個實作多種功能的結構。另一個展現是,不要定義規模過于龐大的結構,這樣不但在運作時浪費系統資源,而且邏輯上難以了解。
(5)除非特别必要,盡量減少變量類型之間的強制轉換。因為強制轉換實際上也是需要計算機額外操作的,過多的強制轉換對系統資源也是一種浪費。
(6)定義結構體時注意優化成員之間的順序,盡量減少因為位元組對齊導緻的存儲空間浪費。
對于可能出現執行錯誤(如打開檔案失敗等)的函數,一律通過傳回值傳回錯誤碼,且錯誤碼用宏定義預先定義好。
除非專門用來設計輸出随機資訊的函數,所有的函數都應當是可預測的,即相同的輸入永遠産生相同的輸出。
一個函數隻完成一個較小的功能,避免出現一個完成大量不相關功能的超長函數。
嚴格區分輸入和輸出參數,對于函數體中不應該改變的參數全部聲明為const類型。
在函數正式開始進行處理之前,檢查輸入參數以及其他用到的外部的有效性。
避免使用過長的參數表,可以把相關的參數封裝成一個結構體并以該結構體作為參數。