林銳C/C++高質量編程指南筆記之一


C/C++高質量編程指南之一

 

第一章:文件結構

1 在文件開頭加上版本信息。

【規則 1-2-1】為了防止頭文件被重復引用,應當用 ifndef/define/endif 結構產生預處理塊

【規則 1-2-2】用 #include <filename.h> 格式來引用標准庫的頭文件(編譯器將從 標准庫目錄開始搜索) 

【規則 1-2-3】用 #include “filename.h” 格式來引用非標准庫的頭文件(編譯器將 從用戶的工作目錄開始搜索) 

【建議 1-2-1】頭文件中只存放“聲明”而不存放“定義” 

第二章:程序的版式

【規則 2-1-1】在每個類聲明之后、每個函數定義結束之后都要加空行。

【規則 2-1-2】在一個函數體內,邏揖上密切相關的語句之間不加空行,其它地方應 加空行分隔。

【規則 2-2-1】一行代碼只做一件事情,如只定義一個變量,或只寫一條語句。

【規則 2-2-2】if、for、while、do 等語句自占一行,執行語句不得緊跟其后。不論 執行語句有多少都要加{}。這樣可以防止書寫失誤

【建議 2-2-1】盡可能在定義變量的同時初始化該變量(就近原則) 

【規則 2-3-1】關鍵字之后要留空格。

【規則 2-3-2】函數名之后不要留空格,緊跟左括號‘(’,以與關鍵字區別

【規則 2-3-5】 “=”、“+=” “>=”、“<=”、“+”、“*”、“%”、“&&”、“||”、“<<”,“^”等二元 操作符的前后應當加空格

【規則 2-3-6】一元操作符如“!”、“~”、“++”、“--”、“&”(地址運算符)等前后不 加空格。 

【建議 2-3-1】對於表達式比較長的 for 語句和 if 語句,為了緊湊起見可以適當地去 掉一些空格,

        如 for (i=0; i<10; i++)和 if ((a<=b) && (c<=d)) 

 

 【規則 2-4-1】程序的分界符‘{’和‘}’應獨占一行並且位於同一列,同時與引用 它們的語句左對齊。

 【規則 2-4-2】{ }之內的代碼塊在‘{’右邊數格處左對齊。 

注意:這個是有爭議的,可能只是在C/C++中這樣去做,在其他語言中好像不是這樣的,

我的習慣是第一個。

 

 

長行拆分:

 

 【規則 2-6-1】應當將修飾符 * 和 & 緊靠變量名

char  *name;  int   *x, y; // 此處 y 不會被誤解為指針 

【規則 2-7-6】注釋的位置應與被描述的代碼相鄰,可以放在代碼的上方或右方,不 可放在下方。 

 第三章:命名規則

這塊好好看看哈。

【規則 3-1-3】命名規則盡量與所采用的操作系統或開發工具的風格保持一致。

例如 Windows 應用程序的標識符通常采用“大小寫”混排的方式,如 AddChild。

而 Unix 應用程序的標識符通常采用“小寫加下划線”的方式,如 add_child。

【規則 3-1-6】變量的名字應當使用“名詞”或者“形容詞+名詞” 。 

float  value; 
float  oldValue; 
float  newValue; 

【規則 3-1-7】全局函數的名字應當使用“動詞”或者“動詞+名詞”(動賓詞組) 。

  類的成員函數應當只使用“動詞”,被省略掉的名詞就是對象本身。 

DrawBox();  // 全局函數  
box->Draw();  // 類的成員函數 

【建議 3-1-1】盡量避免名字中出現數字編號,如 Value1,Value2 等,除非邏輯上的 確需要編號

【規則 3-2-1】類名和函數名用大寫字母開頭的單詞組合而成。 例如: 

 class Node;     // 類名  
class LeafNode;    // 類名  
void  Draw(void);   // 函數名  
void  SetValue(int value); // 函數名 

【規則 3-2-2】變量和參數用小寫字母開頭的單詞組合而成。 

BOOL flag; 
int  drawMode; 

也可以這樣:
string window_name;  // OK 使用下划線
string windowname;   // OK 全部小寫
string windowName;   // Bad 大小寫混合使用
全局變量:沒有特殊要求,盡量少用?可以加上前綴g_以與局部變量區分。

類的成員變量:可以加上前綴m_
當然也有就加一個_的

【規則 3-2-3】常量全用大寫的字母,用下划線分割單詞

const int MAX = 100;  
const int MAX_LENGTH = 100;

【規則 3-2-4】靜態變量加前綴 s_(表示 static)

  static int s_initValue; // 靜態變量 

【規則 3-2-5】如果不得已需要全局變量,則使全局變量加前綴 g_(表示 global)。 

  int g_howMuchMoney; // 全局變量 

【規則 3-2-6】類的數據成員加前綴 m_(表示 member),這樣可以避免數據成員與 成員函數的參數同名。

 第四章:表達式和基本語句

【規則 4-1-1】如果代碼行中的運算符比較多,用括號確定表達式的操作順序,避免 使用默認的優先級。 

與零值比較:

布爾變量與零值比較 

【規則 4-3-1】不可將布爾變量直接與 TRUE、FALSE 或者 1、0 進行比較。 

    假設布爾變量名字為 flag,它與零值比較的標准 if 語句如下:

     if (flag) // 表示 flag 為真 

    if (!flag) // 表示 flag 為假 

 整型變量與零值比較 :

【規則 4-3-2】應當將整型變量用“==”或“!=”直接與 0 比較。

  if (value == 0)   

  if (value != 0)

 浮點變量與零值比較 :

 【規則 4-3-3】不可將浮點變量用“==”或“!=”與任何數字比較。 

千萬要留意,無論是 float 還是 double 類型的變量,都有精度限制。

所以一定要避 免將浮點變量用“==”或“!=”與數字比較,應該設法轉化成“>=”或“<=”形式。 

正確的比較方式

  if ((x>=-EPSINON) && (x<=EPSINON)) 其中 EPSINON 是允許的誤差(即精度) 。

  其中EPSINON是允許的誤差(即精度)。 const float EPSINON = 0.000001,至於為什么取0.000001,可以自己按實際情況定義。

指針變量與零值比較 

【規則 4-3-4】應當將指針變量用“==”或“!=”與 NULL 比較

   if (p == NULL) // p 與 NULL 顯式比較,強調 p 是指針變量   

  if (p != NULL)

 

【建議 4-4-1】在多重循環中,如果有可能,應當將長的循環放在內層,短的 循環放在外層,以減少 CPU 跨切循環層的次數

第五章:常量


為什么需要常量:

如果不使用常量,直接在程序中填寫數字或字符串,將會有什么麻煩?

(1) 程序的可讀性(可理解性)變差。程序員自己會忘記那些數字或字符串是什么意 思,用戶則更加不知它們從何處來、表示什么。

(2) 在程序的很多地方輸入同樣的數字或字符串,難保不發生書寫錯誤。

(3) 如果要修改數字或字符串,則會在很多地方改動,既麻煩又容易出錯。 

【規則 5-1-1】 盡量使用含義直觀的常量來表示那些將在程序中多次出現的數字或 

#define      MAX   100  /*  C 語言的宏常量  */  
const int    MAX = 100;  //  C++ 語言的 const 常量 
const float  PI = 3.14159; //  C++ 語言的 const 常量

const和define的比較

C++ 語言可以用 const 來定義常量,也可以用 #define 來定義常量。但是前者比后 者有更多的優點:

(1) const 常量有數據類型,而宏常量沒有數據類型。編譯器可以對前者進行類型安 全檢查。而對后者只進行字符替換,沒有類型安全檢查,並且在字符替換可能會 產生意料不到的錯誤(邊際效應)。

(2) 有些集成化的調試工具可以對 const常量進行調試,但是不能對宏常量進行調試。


【規則 5-2-1】在 C++ 程序中只使用 const 常量而不使用宏常量,即 const 常量完 全取代宏常量。

【規則 5-3-1】需要對外公開的常量放在頭文件中,不需要對外公開的常量放在定義 文件的頭部。為便於管理,可以把不同模塊的常量集中存放在一個公共的頭文件中。

第六章:函數設計

【規則 6-1-2】參數命名要恰當,順序要合理。 

  應將目的參數放在前面,源參數放在后面。

例如編寫字符串拷貝函數 StringCopy

void StringCopy(char *strDestination,const char *strSource);

調用時:StringCopy(str, “Hello World”);

【規則 6-1-4】如果輸入參數以值傳遞的方式傳遞對象,則宜改用“const &”方式來 傳遞,這樣可以省去臨時對象的構造和析構過程,從而提高效率   

【建議 6-2-1】有時候函數原本不需要返回值,但為了增加靈活性如支持鏈式表達, 

  例如字符串拷貝函數 strcpy 的原型: 

  char *strcpy(char *strDest,const char *strSrc);

  適用於:int  length = strlen( strcpy(str, “Hello World”) );

 

【規則 6-3-1】在函數體的“入口處”,對參數的有效性進行檢查 用assert

 【規則 6-3-2】在函數體的“出口處”,對 return 語句的正確性和效率進行檢查。 

 (1)return 語句不可返回指向“棧內存”的“指針”或者“引用”,因為該內存在函數 體結束時被自動銷毀。

  例如 

char * Func(void) 
 {   
        char str[] = “hello world”; // str 的內存位於棧上   …  
        return str;  // 將導致錯誤  
 }   

(2)要搞清楚返回的究竟是“值” 、“指針”還是“引用” 

(3)如果函數返回值是一個對象,要考慮 return 語句的效率。

  例如       return String(s1 + s2); 

這是臨時對象的語法,表示“創建一個臨時對象並返回它”。

不要以為它與“先創建 一個局部對象 temp 並返回它的結果”是等價的,

如:

  String temp(s1 + s2);

  return temp;  。

實質不然,上述代碼將發生三件事。

首先,temp 對象被創建,同時完成初始化;

然 后拷貝構造函數把 temp 拷貝到保存返回值的外部存儲單元中;

最后,temp 在函數結束 時被銷毀(調用析構函數)。

然而“創建一個臨時對象並返回它”的過程是不同的,編譯 器直接把臨時對象創建並初始化在外部存儲單元中,省去了拷貝和析構的化費,提高了 效率。

 

第七章到最后

 

https://www.cnblogs.com/xiaokang01/p/12716736.html


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM