一、文件結構算法
C/C++程序一般分爲兩個文件,一個文件用於保存程序的聲明,一個文件用於保存程序的實現。數組
1.1 版權和版本的聲明
版權和版本的聲明位於頭文件和定義文件的開頭,主要內容有:
(1)版權信息
(2)文件名稱,標識符,摘要
(3)當前版本號,做者/修改者,完成日期
(4)版本歷史信息安全
1.2 頭文件的結構
頭文件由三部份內容組成:
1)頭文件開頭處的版權和版本聲明。
2)預處理塊。數據結構
3)函數和類結構聲明等。數據結構和算法
1.3 定義文件的結構
定義文件有三部份內容:
1) 定義文件開頭處的版權和版本聲明。
2) 對一些頭文件的引用。
3) 程序的實現體(包括數據和代碼)。ide
1.4 目錄結構
若是一個軟件的頭文件數目比較多(如超過十個),一般應將頭文件和定義文件分別保存於不一樣的
目錄,以便於維護。函數
命名規則
共性規則工具
一、標識符的長度應當符合「min-length && max-information」原則性能
二、程序中不要出現僅靠大小寫區分的類似的標識符。測試
三、程序中不要出現標識符徹底相同的局部變量和全局變量,儘管二者的做用域不一樣而不會
發生語法錯誤,但會令人誤解
四、變量的名字應當使用「名詞」或者「形容詞+名詞」。
五、全局函數的名字應當使用「動詞」或者「動詞+名詞」(動賓詞組)。類的成員函數應
當只使用「動詞」,被省略掉的名詞就是對象自己
六、用正確的反義詞組命名具備互斥意義的變量或相反動做的函數等。
Windows 應用程序命名規則
一、類名和函數名用大寫字母開頭的單詞組合而成
二、變量和參數用小寫字母開頭的單詞組合而成。
三、常量全用大寫的字母,用下劃線分割單詞。
四、靜態變量加前綴s_(表示static)。
五、若是須要定義全局變量,則使全局變量加前綴g_(表示global)。
六、類的數據成員加前綴m_(表示member),這樣能夠避免數據成員與成員函數的參數同名。
七、爲了防止某一軟件庫中的一些標識符和其它軟件庫中的衝突,能夠爲各類標識符加上能
反映軟件性質的前綴。例如三維圖形標準OpenGL 的全部庫函數均以gl 開頭,全部常量(或宏定義)均
以GL 開頭
Linux 應用程序函數命名規則
函數命名應遵循下面兩個原則:
1)屬於某一模塊的函數,加上前綴,前綴爲模塊縮寫;
2)函數名應該代表函數意義,格式爲"前綴_名詞_動詞";
複合表達式
一、不要編寫太複雜的複合表達式。
二、不要有多用途的複合表達式。
三、不要把程序中的複合表達式與「真正的數學表達式」混淆。
if (a < b < c) // a < b < c 是數學表達式而不是程序表達式
並不表示 if ((a<b) && (b<c))
if 語句
1 布爾變量與零值比較
不可將布爾變量直接與TRUE、FALSE 或者一、0 進行比較。
假設布爾變量名字爲flag,它與零值比較的標準if 語句以下:
if (flag) // 表示flag 爲真
if (!flag) // 表示flag 爲假
其它的用法都屬於不良風格,例如:
if (flag == TRUE)
if (flag == 1 )
if (flag == FALSE)
if (flag == 0)
2 整型變量與零值比較
應當將整型變量用「==」或「!=」直接與0 比較。
3 浮點變量與零值比較
不可將浮點變量用「==」或「!=」與任何數字比較。
千萬要留意,不管是float 仍是double 類型的變量,都有精度限制。因此必定要避免將浮點變量
用「==」或「!=」與數字比較,應該設法轉化成「>=」或「<=」形式。
假設浮點變量的名字爲x,應當將
if (x == 0.0) // 隱含錯誤的比較
轉化爲
if ((x>=-EPSINON) && (x<=EPSINON))
其中EPSINON 是容許的偏差(即精度)。
4 指針變量與零值比較
【規則4-3-4】應當將指針變量用「==」或「!=」與NULL 比較。
指針變量的零值是「空」(記爲NULL)。儘管NULL 的值與0 相同,可是二者意義不一樣。假設指針
變量的名字爲p,它與零值比較的標準if 語句以下:
if (p == NULL) // p 與NULL 顯式比較,強調p 是指針變量
if (p != NULL)
不要寫成
if (p == 0) // 容易讓人誤解p 是整型變量
if (p != 0)
或者
if (p) // 容易讓人誤解p 是布爾變量
if (!p)
循環語句的效率
一、在多重循環中,若是有可能,應當將最長的循環放在最內層,最短的循環放在最外層,
以減小CPU 跨切循環層的次數。
二、若是循環體內存在邏輯判斷,而且循環次數很大,宜將邏輯判斷移到循環體的外面。
for 語句的循環控制變量
一、不可在for 循環體內修改循環變量,防止for 循環失去控制。
二、建議for 語句的循環控制變量的取值採用「半開半閉區間」寫法。
switch 語句
1】每一個case 語句的結尾不要忘了加break,
2】不要忘記最後那個default 分支。
常量
1 const 與#define 的比較
(1) const 常量有數據類型,而宏常量沒有數據類型。編譯器能夠對前者進行類型安全檢查。而對後
者只進行字符替換,沒有類型安全檢查,而且在字符替換可能會產生意料不到的錯誤(邊際效應)。
(2) 有些集成化的調試工具能夠對const 常量進行調試,可是不能對宏常量進行調試。
1】儘可能使用含義直觀的常量來表示那些將在程序中屢次出現的數字或字符串。
2】在C++ 程序中只使用const 常量而不使用宏常量,即const 常量徹底取代宏常量
2 常量定義規則
1】須要對外公開的常量放在頭文件中,不須要對外公開的常量放在定義文件的頭部。爲便
於管理,能夠把不一樣模塊的常量集中存放在一個公共的頭文件中。
2】若是某一常量與其它常量密切相關,應在定義中包含這種關係,而不該給出一些孤立的
值。
函數設計
一個函數的註釋信息以下例:
/**********************************************************************************
* Function: calculate The area of rectangle *
* parameter: the Length and Width of
rectangle *
* outout: the area of rectangle *
***********************************************************************************/
int GetValue(int iLength,int iWidth)
{
… … ..
return iArea;
}
1 參數的規則
1】參數的書寫要完整,不要貪圖省事只寫參數的類型而省略參數名字。若是函數沒有參數,
則用void 填充。
2】參數命名要恰當,順序要合理。
3】若是參數是指針,且僅做輸入用,則應在類型前加const,以防止該指針在函數體內被意
外修改
4】若是輸入參數以值傳遞的方式傳遞對象,則宜改用「const & 」方式來傳遞,這樣能夠省
去臨時對象的構造和析構過程,從而提升效率。
5】參數缺省值只能出如今函數的聲明中,而不能出如今定義體中。
6】若是函數有多個參數,參數只能從後向前挨個兒缺省,不然將致使函數調用語句怪模怪
樣
7】避免函數有太多的參數,參數個數儘可能控制在5 個之內。若是參數太多,在使用時容易
將參數類型或順序搞錯。
8】儘可能不要使用類型和數目不肯定的參數。
2 返回值的規則
1】不要省略返回值的類型。
2】函數名字與返回值類型在語義上不可衝突
3】不要將正常值和錯誤標誌混在一塊兒返回。正常值用輸出參數得到,而錯誤標誌用return 語
句返回
4】給以「指針傳遞」方式的函數返回值加 const 修飾,那麼函數返回值(即指針)的內容
不能被修改,該返回值只能被賦給加 const 修飾的同類型指針。
5】函數返回值採用「值傳遞方式」,因爲函數會把返回值複製到外部臨時的存儲單元中,
加 const 修飾沒有任何價值。
6】函數返回值採用「引用傳遞」的場合並很少,這種方式通常只出如今類的賦值函數中,
目的是爲了實現鏈式表達。
3 函數內部實現的規則
1】在函數體的「入口處」,對參數的有效性進行檢查。
2】在函數體的「出口處」,對return 語句的正確性和效率進行檢查。
(1)return 語句不可返回指向「棧內存」的「指針」或者「引用」,由於該內存在函數體結束時被自
動銷燬。
(2)要搞清楚返回的到底是「值」、「指針」仍是「引用」。
(3)若是函數返回值是一個對象,要考慮return 語句的效率。
其它建議
1】函數的功能要單一,不要設計多用途的函數。
2】函數體的規模要小,儘可能控制在50 行代碼以內。
3】儘可能避免函數帶有「記憶」功能。相同的輸入應當產生相同的輸出。帶有「記憶」功能
的函數,其行爲多是不可預測的,由於它的行爲可能取決於某種「記憶狀態」。這樣的函數既不易理
解又不利於測試和維護。在C/C++語言中,函數的static 局部變量是函數的「記憶」存儲器。建議儘可能
少用static 局部變量,除非必需
4】不只要檢查輸入參數的有效性,還要檢查經過其它途徑進入函數體內的變量的有效性,
例如全局變量、文件句柄等。
5】用於出錯處理的返回值必定要清楚,讓使用者不容易忽視或誤解錯誤狀況
引用與指針的比較
引用是C++中的概念,容易把引用和指針混淆。
引用的一些規則以下:
(1)引用被建立的同時必須被初始化(指針則能夠在任什麼時候候被初始化)。
(2)不能有NULL 引用,引用必須與合法的存儲單元關聯(指針則能夠是NULL)。
(3)一旦引用被初始化,就不能改變引用的關係(指針則能夠隨時改變所指的對象)
普通函數重載
1】重載函數中的參數不一樣(包括類型、順序不一樣),纔是重載函數,而僅僅返回值不一樣
則不行。
2】小心隱式類型轉換致使重載函數產生二義性,數字自己沒有類型,將數字看成參數時
將自動進行類型轉換(稱爲隱式類型轉換)。
成員函數的重載、覆蓋與隱藏
1】成員函數的重載、覆蓋(override)與隱藏很容易混淆,注意區分。
2】注意若是派生類的函數與基類的函數同名,可是參數不一樣。此時,不論有無 virtual
關鍵字,基類的函數將被隱藏(注意別與重載混淆)。
3】注意若是派生類的函數與基類的函數同名,而且參數也相同,可是基類函數沒有
virtual 關鍵字。此時,基類的函數被隱藏(注意別與覆蓋混淆)
內聯函數
1】儘可能用內聯取代宏代碼,提升函數的執行效率(速度)。
2】關鍵字 inline 必須與函數定義體放在一塊兒才能使函數成爲內聯,僅將 inline 放在函
數聲明前面不起任何做用。
3】若是函數體內的代碼比較長或函數體內出現循環,則不宜使用內聯
內存管理
內存分配方式有三種:
(1) 從靜態存儲區域分配。內存在程序編譯的時候就已經分配好,這塊內存在程序的整個運行期間都
存在。例如全局變量,static 變量
(2) 在棧上建立。在執行函數時,函數內局部變量的存儲單元均可以在棧上建立,函數執行結束時這
些存儲單元自動被釋放。棧棧內存分配運算內置於處理器的指令集中,效率很高,可是分配的內存容量有
限。
(3) 從堆上分配,亦稱動態內存分配。程序在運行的時候用malloc 或new 申請任意多少的內存,程
序員本身負責在什麼時候用free 或delete 釋放內存。動態內存的生存期由咱們決定,使用很是靈活,但問
題也最多
1】用malloc 或new 申請內存以後,應該當即檢查指針值是否爲NULL。防止使用指針值爲NULL
的內存。
2】不要忘記爲數組和動態內存賦初值。防止將未被初始化的內存做爲右值使用。
3】避免數組或指針的下標越界,特別要小心發生「多1」或者「少1」操做。
4】動態內存的申請與釋放必須配對,防止內存泄漏。
5】用free 或delete 釋放了內存以後,當即將指針設置爲NULL,防止產生「野指針」。
類的構造函數
1】「缺省的拷貝構造函數」和「缺省的賦值函數」均採用「位拷貝」而非「值拷貝」的方式來實現,若類中含有指針變量,不能採用缺省的方式
2】若是類存在繼承關係,派生類必須在其初始化表裏調用基類的構造函數。
3】類的 const 常量只能在初始化表裏被初始化,由於它不能在函數體內用賦值的方式來初始化。
4】非內部數據類型的成員對象採用初始化表的方式初始化較好。
5】拷貝構造函數和賦值函數很是容易混淆,常致使錯寫、錯用。拷貝構造函數是在對象被建立時調用的,而賦值函數只能被已經存在了的對象調用
成員函數
1】任何不會修改數據成員的函數都應該聲明爲 const 類型
類的繼承和組合
1】若是類 A 和類 B 絕不相關,不能夠爲了使 B 的功能更多些而讓 B 繼承 A 的功能和屬性
2】若在邏輯上 B 是 A 的「一種狀況」,則容許 B 繼承 A 的功能和屬性。
3】若在邏輯上 A 是 B 的「一部分」(a part of),則不容許 B 從 A 派生,而是要用 A 和其它東西組合出 B
提升程序的效率
1】不要一味地追求程序的效率,應當在知足正確性、可靠性、健壯性、可讀性等質量因素的前提下,設法提升程序的效率。
2】以提升程序的全局效率爲主,提升局部效率爲輔。
3】在優化程序的效率時,應當先找出限制效率的「瓶頸」,不要在可有可無之處優化。
4】先優化數據結構和算法,再優化執行代碼。
5】有時候時間效率和空間效率可能對立,此時應當分析那個更重要,做出適當的折衷。例如多花費一些內存來提升性能
6】不要追求緊湊的代碼,由於緊湊的代碼並不能產生高效的機器碼。