理解C語言——從小菜到大神的晉級之路(15)——完結篇:C程式設計風格
本期視訊連結:點選這裡
有人說過:“程式原始碼其實是跟人閱讀的,只是恰好機器可以編譯而已”。程式設計初學者常常會有這樣一個觀念,就是我的程式只要編譯通過了,執行沒有問題那就萬事大吉了。至於程式碼的編寫規不規範,完全就是無關緊要的小事情。如果是處於學習階段,比如為了完成在學校的C語言課的作業,那麼花心思在程式碼規範上的確沒有特別的必要,因為這些程式碼基本不會進入實用工程,也不會被很多人閱讀到。
但是,如果應用到了工程領域,比如在軟體/網際網路企業的技術研發部門,或者Github等平臺上的開源工程,那麼程式設計的規範性將變得無比重要。因為在這些場合,你寫的程式碼將被許多人閱讀,並且可能會成為許多人進行後續開發的基礎。此時,差勁的程式碼風格將嚴重拉低其他開發人員的工作效率。因此,我們推薦從一開始學習便養成一個良好的程式設計習慣,維持一個合理的程式碼風格,這樣對未來的工作大有裨益。
C語言程式設計風格的內容相當龐大,這裡只挑選一部分相對常用而且比較重要的內容作為參考,主要分為5個部分,包括排版、註釋、命名、變數/結構、函式等。
1、排版
程式排版使得程式碼的結構更加清晰明瞭,而且有助於理解上下文的邏輯關係。
(1)程式塊應根據上下文關係採用縮排風格,縮排的長度根據具體標準規定;
(2)獨立的程式塊之間、變數說明之後必須加空行;比如:
int fun()
{
int nVal1 = 0, nVal2 = 5, nSum;
{
nSum = nVal1 + nVal2;
}
printf("Sum is %d \n", nSum);
}
(3)一條語句佔一行,不允許將兩條語句寫在一行中;
(4)對於存在判斷、迴圈的程式碼,像if/for/do/while/case/swith/default等部分獨佔一行,且無論執行部分有多少條語句,都必須使用大括號{ };
(5)包裹程式碼塊的大括號{ }必須另起一行,不要跟隨上一行程式碼的末尾;且大括號也要符合程式碼縮排規則;
2、註釋
註釋雖然不影響程式的執行,但仍然是程式碼的重要組成部分。完善的程式碼註釋對快速理解程式碼的功能具有重要意義,相反如果程式碼邏輯複雜且沒有註釋,或註釋不完整、不科學,那麼旁人很難理解這段程式碼究竟是做什麼的。需注意一點,別人無法理解的程式即使執行良好,也永遠都是垃圾程式碼。
添加註釋需要注意,註釋應簡潔、有效,有助於提升對程式碼的理解。所以添加註釋應注意不要新增一些完全無意義或者錯誤的資訊。通常,我們認為一套程式碼按照優劣分為4個等級:
第一等級:不需要註釋,通過優秀的程式碼風格、識別符號命名和程式碼的上下文關係就可以達到高可讀性的程式碼;
第二等級:程式碼的命名和組織規範、風格稍顯不足,但有完善的註釋;
第三等級:程式碼風格和註釋都不夠完善,但是組織了較為完善的文件在一定程度彌補了這一缺陷;
第四等級:程式碼風格、註釋和文件都不足,這種就屬於其他人難以理解的垃圾程式碼。
函式頭部的註釋:
在函式頭部應添加註釋,說明函式的功能、引數、返回值等資訊。下面的註釋格式比較完善,不一定要侷限與此,但建議保留其中的大部分資訊:
/*************************************************
Function: // 函式名稱
Description: // 函式功能、效能等的描述
Calls: // 被本函式呼叫的函式清單
Called By: // 呼叫本函式的函式清單
Input: // 輸入引數說明,包括每個引數的作
// 用、取值說明及引數間關係。
Output: // 對輸出引數的說明。
Return: // 函式返回值的說明
Others: // 其它說明
*************************************************/
程式碼中的註釋:
語句的註釋應在被註釋語句的正上方或右方。如果是在上方的話,除非十分必要否則不要再程式碼和註釋之間插入空格。
對於具有物理含義的常量和變數,以及資料結構,除非命名本身是充分註釋的,在宣告時必須加以註釋。
全域性變數要有詳細的註釋,包括對其功能、取值範圍、使用的函式以及存取時的注意事項等。
註釋與上方的程式碼用一行空格間隔。
對選擇、迴圈語句應當添加註釋,說明分支、迴圈體的意義。
在程式塊結束的大括號右方添加註釋,說明匹配的程式塊開始位置。
如以下程式碼:
if (...)
{
program code
while (index < MAX_INDEX)
{
program code
} /* end of while (index < MAX_INDEX) */ // 指明該條while語句結束
} /* end of if (...)*/ // 指明是哪條if語句結束
3、識別符號命名
識別符號命名是程式碼風格中的重要組成部分,甚至直接決定了程式碼可讀性的高低。最常用的識別符號無非就是常量名、變數/結構體名、函式名、巨集定義、標籤名等。對不同的識別符號型別一般適用不同的要求,但有一些基本要求是一致的:識別符號的命名必須清晰明瞭,含義明確,儘量少地使用縮寫;嚴禁使用無意義的單個字母如a, b, i, m, n或者func1, fun等無意義的單詞或縮寫用於命名;
(1)常量、變數、函式命名:
對於變數名和函式名,通常比較常用的有兩種命名法:駝峰命名法和下劃線命名法,這兩種方法的根本區別在於通過怎樣的方式來分隔識別符號命名中的邏輯斷點。
駝峰命名法:通過大小寫字母的變化進行分隔,如:int imgWidth = 0; char *studentName = “Jerry”;
下劃線命名法:通過下劃線進行分隔,如:double earth_moon_distance;
對於函式名和變數名,一般可以使用不同的命名方法,但是需要注意的是隻要選定的命名規範就要從頭到尾保持不變。通常,我個人的習慣是,變數名和結構體名使用駝峰命名法,變數名用小寫開頭,結構體用大寫開頭;函式名使用下劃線命名法,公有API以大寫字母開頭,私有函式以小寫開頭並宣告為static型別。
另外,對於常量、結構體成員變數、全域性變數,還可以參考匈牙利命名法的原則,在變數名前加入字首c_、m_和g_。
(2)巨集定義命名
對於巨集定義的命名,一律全部使用大寫字母,邏輯斷點採用下劃線分隔,如
#define MAX_ARRAY_LENGTH 256
對於標頭檔案保護作用的巨集定義,則以標頭檔案的檔名命名,邏輯斷點和副檔名前的點全部用下劃線替代,並且在首位各新增一個下劃線,如
//ImageProcessing.h
#ifndef _IMAGE_PROCESSING_H_
#define _IMAGE_PROCESSING_H_
/*code*/
#endif
(3)標籤名
通常標籤名配合goto語句一起使用。由於goto本來就是比較冷門的語句,標籤也不是很常用。如果用到,則全部使用小寫字母,並且在結尾加_label,如:
void test()
{
/*code*/
goto end_label;
/*code*/
end_label:
/*code*/
}
4、變數和結構使用規範
變數和結構的使用是程式設計中最為頻繁的動作,如果能正確規範變數的使用,那麼對整體的程式設計風格的提升大有幫助。
(1)變數定義之後立刻初始化。通常數值型變數定以後可以立刻初始化為0、某個負數或其他無意義的數值,指標變數定義後立刻初始化為NULL。這樣在後面使用變數時可以更方便地判斷變數是否已經被正確地處理,防止無意中使用了未經初始化的值。
(2)除非特別必要,否則儘量減少全域性變數的使用,對於跨檔案使用的全域性變數更要慎重。全域性變數是造成程式碼之間耦合的重要因素,通常使用全域性變數越多,程式碼就越難以維護。
(3)對於數值完全不應當改變的量,一律定義為常量,防止被誤修改。
(4)定義一個結構體的功能應當越具體越好,不應定義一個實現多種功能的結構。另一個體現是,不要定義規模過於龐大的結構,這樣不但在執行時浪費系統資源,而且邏輯上難以理解。
(5)除非特別必要,儘量減少變數型別之間的強制轉換。因為強制轉換實際上也是需要計算機額外操作的,過多的強制轉換對系統資源也是一種浪費。
(6)定義結構體時注意優化成員之間的順序,儘量減少因為位元組對齊導致的儲存空間浪費。
5、函式使用規範
- 對於可能出現執行錯誤(如開啟檔案失敗等)的函式,一律通過返回值返回錯誤碼,且錯誤碼用巨集定義預先定義好。
- 除非專門用來設計輸出隨機資訊的函式,所有的函式都應當是可預測的,即相同的輸入永遠產生相同的輸出。
- 一個函式只完成一個較小的功能,避免出現一個完成大量不相關功能的超長函式。
- 嚴格區分輸入和輸出引數,對於函式體中不應該改變的引數全部宣告為const型別。
- 在函式正式開始進行處理之前,檢查輸入引數以及其他用到的外部的有效性。
- 避免使用過長的引數表,可以把相關的引數封裝成一個結構體並以該結構體作為引數。
相關推薦
理解C語言——從小菜到大神的晉級之路(15)——完結篇:C程式設計風格
本期視訊連結:點選這裡 有人說過:“程式原始碼其實是跟人閱讀的,只是恰好機器可以編譯而已”。程式設計初學者常常會有這樣一個觀念,就是我的程式只要編譯通過了,執行沒有問題那就萬事大吉了。至於程式碼的編寫規不規範,完全就是無關緊要的小事情。如果是處於學習階段,比如
大資料晉級之路(7)Storm安裝及使用
一、Apache Storm簡介 Apache Storm簡介 Storm是一個分散式的,可靠的,容錯的資料流處理系統。Storm叢集的輸入流由一個被稱作spout的元件管理,spout把資料傳遞給bolt, bolt要麼把資料儲存到某種儲存器,要麼把資料傳遞
大資料晉級之路(5)Hadoop,Spark,Storm綜合比較
大資料框架:Spark vs Hadoop vs Storm 目錄 Hadoop Spark Storm 大資料時代,TB級甚至PB級資料已經超過單機尺度的資料處理,分散式處理系統應運而生。 知識預熱 「專治不明覺厲」之“大資料
理解C語言——從小菜到大神的晉級之路(3)——C源程式的基本結構與除錯方法
本期視訊點選這裡 在上一篇中,我們進行了Visual Studio 2013的安裝以及第一個demo程式“HelloWorld”的建立。現在我們看一下其中的原始碼及相關的C語言基
理解C語言——從小菜到大神的晉級之路(8)——陣列、指標和字串
本期視訊點選這裡 在前面幾次我們接觸的資料型別都是簡單資料型別,使用一個數據個體表示一個元素。C語言中還提供了多種複雜資料型別,其中最簡單的一種就是陣列。陣列這一結構使用記憶體中一段連續的記憶體空間儲存一組相同型別的變數,這些變數通過陣列的下標/索引的不同相
求最長迴文串-從動態規劃到"馬拉車"之路(下)
預備知識: (1)在一個數軸上有兩點i和j(i<=j)關於點m對稱,那麼有 i = 2m-j; 證明: 因為 i<=j 且 i 和 j 關於 m 對稱,那麼有 (i + j)/ 2 = m 所以 i = 2m - j; (2)迴文串的對稱性: 由迴文串的
C++學習之路(15)---C++ 資源大全(太全了)
C++是在C語言的基礎上開發的一種集面向物件程式設計、泛型程式設計和過程化程式設計於一體的程式語言。應用較為廣泛,是一種靜態資料型別檢查的,支援多重程式設計的通用程式設計語言。 關於 C++ 框架、庫和資源的一些彙總列表。 內容包括:標準庫、Web應用框架、人工智慧、
React 從入門到進階之路(七)
之前的文章我們介紹了 React 表單詳解 約束性和非約束性元件 input text checkbox radio select textarea 以及獲取表單的內容。接下來我們將介紹 React中的元件、父子元件、React props父元件給子元件傳值、子元
React 從入門到進階之路(八)
之前的文章我們介紹了 React中的元件、父子元件、React props父元件給子元件傳值、子元件給父元件傳值、父元件中通過refs獲取子元件屬性和方法。接下來我們將介紹 React propTypes defaultProps。 之前我們已經根據
React 從入門到進階之路(九)
之前的文章我們介紹了 React propTypes defaultProps。接下來我們將介紹 React 生命週期函式。 之前我們已經根據 create-react-app 模組建立了一個 React 專案,並定義 App.js 為根元件,即父元件,Home.js 為子元
koa2 從入門到進階之路 (一)
首先我們先來了解一下 Koa 是什麼,https://koa.bootcss.com/,這是 Koa 的官方網站,映入眼簾的第一句就是 Koa -- 基於 Node.js 平臺的下一代 web 開發框架。 在學習 Koa 之前我們應對 Node.js 有一定的基礎,我們都知道: No
koa2 從入門到進階之路 (二)
之前的文章我們已經能夠在本地啟動一個簡單的專案,本章我們來看一下 koa 路由,get 傳值,動態路由。 一、Koa 路由 路由(Routing)是由一個 URI(或者叫路
koa2 從入門到進階之路 (三)
之前的文章我們介紹了一下 koa 路由,get 傳值,動態路由,本節我們看一下 koa 中介軟體 以及 koa 中介軟體的洋蔥圖執行流程。 一、什麼是 Koa 的中介軟體 通俗的講:中介軟體就是匹配路由之前或者匹配路由完成做的一系列的操作,我們就可以把它叫做中介軟體。
koa2 從入門到進階之路 (四)
之前的文章我們介紹了一下 koa 中介軟體 以及 koa 中介軟體的洋蔥圖執行流程,本篇文章我們來看一下 koa 中使用 ejs 模板及頁面渲染。 在 Express 中,我們經常會用 ejs 模板來渲染前端頁面,在 koa 中同樣可以使用 ejs 模板引擎,關於 ejs 模板引擎的用法這裡就不做過多說明了
koa2 從入門到進階之路 (五)
之前的文章我們介紹了一下 koa 中使用 ejs 模板及頁面渲染,本篇文章我們來看一下 koa post提交資料及 koa-bodyparser中介軟體。 在前端頁面中,不免會用到 form 表單和 post 請求向後端提交資料,接下來我們看一下 koa 是如何獲取到前端通過 post 請求傳過來的資料。
koa2 從入門到進階之路 (六)
之前的文章我們介紹了一下 koa post提交資料及 koa-bodyparser中介軟體,本篇文章我們來看一下 koa-static靜態資源中介軟體。 我們在之前的目錄想引入外部的 js,css,img 等靜態資源該如何獲取呢?我們首先先按照之前的思維按照相對路徑去查詢,如下圖:
koa2 從入門到進階之路 (七)
之前的文章我們介紹了一下 koa koa-static靜態資源中介軟體,本篇文章我們來看一下 koa 中 cookie 和 session 的使用。 cookie 是儲存於訪問者的計算機中的變數。可以讓我們用同一個瀏覽器訪問同一個域名的時候共享資料。
Python 從入門到進階之路(二)
之前的文章我們對 Python 語法有了一個簡單的認識,接下來我們對 Python 中的 if while for 做一下介紹。 上圖為 if 判斷語句的流程,無論任何語言,都會涉及到判斷問題,if 條件會進行 true 和 false 的判斷,如下: 1 num = 10 2 if num =
Python 從入門到進階之路(三)
在之前的文章我們介紹了一下 Python 中 if while for 的使用,本章我們來看一下 Python 中的變數型別。 在 Python 定義變數時的規則是 變數名 = 變數 ,Python 中的變數賦值不需要型別宣告。每個變數在記憶體中建立,都包括變數的標識,名稱和資料這些資訊。每個變數在使用前都
Python 從入門到進階之路(四)
之前的文章我們簡單介紹了一下 Python 的幾種變數型別,本篇文章我們來看一下 Python 中的函式。 函式是組織好的,可重複使用的,用來實現單一,或相關聯功能的程式碼段。 函式能提高應用的模組性,和程式碼的重複利用率。你已經知道Python提供了許多內建函式,比如print()。但你也可以自己建立函