CC++語言編碼規範

                                                                         CC++語言編碼規範

1.    命名規則

1.1. 起個合適的名字

1.1.1.    類的名稱(適用於C++)

²  類的名稱要能告訴我們,這個類是什麼。因此,類的名稱通常是名詞。

²  類的名字不需要告訴我們,它從哪個類繼承而來的。

²  有時候加個後綴是很有用的。比如類是一個代理(Agents)時,起名叫DownloadAgent更能表達真實的意圖。

1.1.2.    方法和函數的名稱(適用於C/C++)

²  方法和函數通常都要執行某種行爲,因此,名稱要能清楚的說明它做什麼:CheckForErrors() 而不是ErrorCheck(),DumpDataToFile() 而不是 DataFile()。 這樣也可以很容易的區別函數和數據。

²  函數名總以動詞開頭,後面跟隨其它名稱。這樣看起來更自然些。

²  可以加一些必要的後綴:

Max – 表示取最大值

Cnt – 表示當前的計數值

Key – 表示鍵值

例如:RetryMax 表示可接收的最大數,RetryCnt表示當前接收的數量。

²  前綴也同樣有用:

Is – 用於詢問一些問題。只要看到Is開頭,就知道這是一個查詢。

Get – 用於獲取一個值。

Set – 用於設置一個值。

例如:IsHitRetryLimit.

1.1.3.   含有度量單位的名稱(適用於C/C++)

 

²  如果一個變量用於表示時間,重量或其它度量單位,應把度量單位添加到名稱中,以便開發人員更早一步發現問題。

例如:

uint32 mTimeoutMsecs;

uint32 mMyWeightLbs;

1.1.4.    縮寫名稱不要全部大寫(適用於C/C++)

²  無論是什麼縮寫名稱,我們總以一個大寫字母開頭,後面跟隨的字母全部用小寫。

例如:

class FluidOz;            // 而不是 FluidOZ

class NetworkAbcKey;      // 而不是 NetworkABCKey

1.2.類的命名(適用於C++)

²  用大寫字母作爲單詞的分隔,每個單詞的首字母大寫,其它字母均小寫。

²  名字的第一個字母應大寫

²  不含有下劃線 ('_')

例如:

   class NameOneTwo; 

   class Name;

1.3.類庫(或程序庫)命名 (適用於C/C++)

²  使用命名空間防止名字衝突。

²  如果編譯器沒有實現命名空間,需要用前綴來避名名字衝突,不過前綴不要過長(2個字母比較好)。

例如:

John Johnson 完成了一個數據結構的庫,它可以使用JJ作爲庫的前綴,所以類名就象下面這樣:

   class JjLinkList

   {

   }

1.4.方法和函數的命名(適用於C++)

²  使用與類名相同的規則

例如:

   class NameOneTwo

   {

   public:

      int     DoIt();

      void    HandleError();

   }

1.5.類屬性的命名(適用於C++)

²  屬性(通常是非公有數據成員)名字以字母'm'開頭。

²  在 'm(m_)'  後面,使用與類名相同的規則。

²  'm(m_)' 總是位於其它修飾符(如表示指針的 'p')的前面。

例如:

   class NameOneTwo

   {

   public:

      int     VarAbc();

      int     ErrorNumber();

   private:

      int          mVarAbc;

      int          mErrorNumber;

      String*      mpName;

   }

1.6.方法和函數參數的命名(適用於C++)

²  第一個字母必須小寫。

²  第一個字母后面的單詞使用與類名相同的規則。

例如:

   class NameOneTwo

   {

   public:

      int     StartYourEngines(

                               Engine&rSomeEngine,

                              Engine&rAnotherEngine);

   }

1.7.局部變量的命名(適用於C/C++)

²  所有字母都用小寫

²  使用下劃線 '_' 作爲單詞的分隔。

例如:

   int

  NameOneTwo::HandleError(int errorNumber)

   {

      int            error= OsErr();

      Time           time_of_error;

     ErrorProcessor error_processor;

   }

 

1.8.指針變量的命名前綴(適用於C/C++)

²  指針變量多數情況應在前面加 'p'。

²  星號 '*' 應靠近類型,而不是變量名。

例如:

  String* pName=new String;

 

 

  特別的:String* pName, name; 應分成兩行來寫:

  String* pName;

  String  name;

1.9.引用變量和返回引用函數的命名前綴(適用於C++)

²  引用必須用 'r'作前綴修飾。

例如:

   class Test

   {

   public:

      void               DoSomething(StatusInfo&rStatus);

      StatusInfo&        rStatus();

      constStatusInfo&  Status() const; // 這裏返回的是常量引用,所以不符合本規則

   private:

     StatusInfo&        mrStatus;

   }

 

1.10.   全局變量的命名前綴(適用於C/C++)

²  全局變量總是以 'g(g_)' 作爲前綴。

例如:

    Logger g_Log;

    Logger* g_pLog;

1.11.   全局常量的命名(適用於C/C++)

²  全局常量全部大寫,並以下劃線 '_' 分隔單詞。

例如:

    const intA_GLOBAL_CONSTANT = 5;

1.12.   靜態變量的命名前綴(適用於C++)

 

²  靜態變量以 's' 作爲前綴。

例如:

   class Test

   {

   public:

   private:

      staticStatusInfo m_sStatus;

   }

1.13.   自定義類型(typedef)的命名(適用於C/C++)

²  類型定義名稱指的是用typedef定義的名稱。

²  類型定義名稱使用與類名相同的規則,並使用Type作爲後綴。

例如:

   typedefuint16  ModuleType;

   typedefuint32  SystemType;

1.14.   宏定義的命名(適用於C/C++)

²  所有單詞的字母都用大寫,並使用下劃線 '_' 分隔.

例如:

#define MAX(a,b) blah

#define IS_ERR(err) blah

1.15.   C 函數的命名(適用於C/C++)

²  C++項目中,應儘量少用C函數。

²  C函數使用GNU規範,所有字母都使用小寫,並用下劃線 '_' 作爲單詞的分隔。

例如:

   int

  some_bloody_function()

   {

 

   }

²  特別的,爲了賺容C/C++,在必要的時候,在C++中應以下面的格式定義C函數:

   extern “C” int some_bloody_function();

²  或在C/C++中推薦使用下面的格式:

   #ifdef__cplusplus__

   extern “C”{

   #endif

   int

  some_bloody_function()

   {

   }

   #ifdef__cplusplus__

   }

   #endif

1.16.   枚舉的命名(適用於C/C++)

²  所有字母都大寫,並用下劃線 '_' 作爲單詞分隔。

例如:

 

   enumPinStateType

   {

      PIN_OFF,

      PIN_ON

   };

 

enum { STATE_ERR, STATE_OPEN, STATE_RUNNING, STATE_DYING};

2.    排版規則

2.1. 佈局和模板

2.1.1.    類的佈局模板 (適用於C++)

 

²  請使用下面的模板來創建一個新的類:

/**     

 * 用一行來描述類

 *

 *#include "XX.h" <BR>

 *-llib

 *

 * 類的詳細說明

 * 

 * @seesomething

 */

 

 

 

#ifndef SORUTION_PROJECT_CLASSNAME_H

#define SORUTION_PROJECT_CLASSNAME_H

// 在這裏包含系統頭文件

//

// 在這裏包含項目頭文件

//

 // 在這裏包含局部頭文件

//

// 在這裏放置前置引用

//

 

 

 

 

 

class XX

{

public:

    // 類的生命週期控制函數,如構造和析構,以及狀態機

    /**

    *Default constructor.

    */

    XX(void);

     /**

    *Copy constructor.

    *

    *@param from The value to copy to this object.

    */

    XX(const XX& from);

    /**

    *Destructor.

    */

    virtual ~XX(void);

    // 在這裏放置類的運算操作符

    /**

    *Assignment operator.

    *

    *@param from THe value to assign to this object.

            *

    *@return A reference to this object.

    */

 

    XX&                     operator=(XX&from); 

    // 在這裏放置類的操作                      

    // 在這裏放置屬性存取

             // 在這裏放置類的狀態查詢

protected:

private:

};

// 內聯方法定義

//

// 外部引用

//

#endif  // SORUTION_PROJECT_CLASSNAME_H

²  定義的順序是: public, protected, private

²  要清楚public/protected/private都應該放置哪些東西

2.1.2.   源文件格式(適用於C++)

#include "XX.h"                               // class implemented

 

/////////////// PUBLIC///////////////////////

//================= 構造函數 ====================

XX::XX()

{

 

}// XX

XX::XX(const XX&)

{

}// XX

 

 

 

XX::~XX()

{

}// ~XX

//=============== 操作符=========================

 

XX&

 

XX::operator=(XX&);

 

{

 

   return *this;

}// =

//==============類的操作 =====================

 

//==============屬性存取 =====================

 

//==============狀態查詢   =====================

 

///////////// PROTECTED  //////////////////

///////////// PRIVATE    //////////////////

 

2.1.3.    保護頭文件不被重複包含 (適用於C/C++)

²  應使用宏定義來保護頭文件不被重複包含:

#ifndef SORUTION_PROJECT_CLASSNAME_H

#define SORUTION_PROJECT_CLASSNAME_H

 

 

 

#endif // SORUTION_PROJECT_CLASSNAME_H

²  如果使用命名空間的時候,要把命名空間加到文件名前面:

#ifndef SORUTION_PROJECT_NAMESPACE_CLASSNAME_H

#define SORUTION_PROJECT_NAMESPACE_CLASSNAME_H

#endif

2.1.4.    方法和函數的佈局 (適用於C/C++)

²  對於有較多參數的函數的寫法

如果參數較多,一行寫不下,我們應該分成幾行來寫,並且每個參數都另起一行對齊:

 

   int AnyMethod(

                 int  arg1, 

                 int   arg2,

                 int   arg3,

                 int   arg4); 或

int AnyMethod( int   arg1 

               , int   arg2

               , int   arg3

               , int   arg4);

2.2. 縮進、製表符以及空格 (適用於C/C++)

²  縮進的時候,每一層縮進3,4,或8個空格。(推薦使用4個空格)

²  不要使用TAB,用空格,大多數編輯器可以用空格代替TAB。TAB應固定4個空格,因爲大多數編輯器都是這麼設置的。

²  雖然沒有規定縮進的層次,但是4至5層是合適的。如果縮進的層次太多,你可能需要考慮是否進行代碼重構了。

例如:

   void

   func()

   {

      if (something bad)

      {

          if (another thing bad)

          {

              while (more input)

              {

              }

          }

      }

   }

2.3. 儘量使一行不要超過78個字母 (適用於C/C++)

²  有許多編輯器屏幕只有78個字母寬

2.4. 保證一行只寫一條語句 (適用於C/C++)

²  一行最多隻寫一條語句

²  一行只定義一個變量

例如:

不要象下面這樣:

char** a, *x;

int width, height; //widthand height of image

要象這樣:

char** a= 0;  // 文檔說明

char*  x= 0;  // 文檔說明

2.5. 花括號 {} 規則 (適用於C/C++)

2.5.1.    花括號的位置

²  在關鍵字的下一行單獨放置括號,並且與關鍵字對齊,如:

 

if (condition)       

{

    ...

}

while (condition)

{

    …

}

2.5.2.    什麼時候應使用花括號

所有的 if, while 和 do 語句,要麼用單行格式,要麼使用花括號格式。

²  使用花括號格式:

if (1 == somevalue)

{

   somevalue = 2;

}

²  單行格式:

if (1 == somevalue) somevalue = 2;

或下面這樣(對於這種寫法,建議使用花括號):

if (1 == somevalue)

{

somevalue = 2;

}

2.5.3.    在花括號結束的位置加上註釋

²  在花括號結束的位置加上註釋是一個好習慣。假如前後花括號距離很遠,註釋就能幫你理解它是如何對應的。如:

while(1)

{

   if (valid)

   {

 

   } // if valid

   else

   {

   } // not valid

} // end forever

2.5.4.    注意屏幕大小

²  一個語句塊儘量不超過一個屏幕大小,這樣,不要捲動屏幕就可以閱讀代碼。

2.6.圓括號 () 規則 (適用於C/C++)

²  圓括號與關鍵字之間應放一個空格。

²  圓括號與函數名之間不要有空格。

²  Return 語句不要使用圓括號。

例如:

    if (condition)

    {

    }

   while(condition)

    {

    }

    strcpy(s, s1);

    return 1;

2.7.if else 語句的格式 (適用於C/C++)

²  佈局

   if (條件)               // 註釋

   {

  }

   else if (條件)           // 註釋

   {

   }

   else                   // 註釋

   {

   }

²  條件格式

總是把常量放在等號或不等於號的左邊:

if ( 6 == errorNum ) ...

一個很重要的理由是,假如漏寫一個等號,這種寫法會產生一個編譯錯誤,有助於馬上發現問題。

比如:

if ( errorNum == 6) ...

錯寫成:

if ( errorNum = 6) ... // 這是一個不容易發現的災難

2.8.switch 格式 (適用於C/C++)

²  直通的case語句,應該放置一條註釋說明這個case語句是直通到下一個case語句的。

²  總是要寫default語句,不管是否是需要。

²  在case中需要定義變量的時候,應把所有代碼放在語句塊中。

例如:

switch (...)

{

case 1:

    ...

        // 繼續執行case2

case 2:

    {       

        int v;

        ...

    }

   break;

default:

}

2.9. 使用goto,continue,break 和 ?: (適用於C/C++)

2.9.1.    Goto

²  儘量避免使用Goto 語句。一個合理使用goto語句的場合是,當你需要從多層循環中跳出。例如:

for (...)

{

    while (...)

    {

        ...

            if (disaster)

goto error; //跳出循環

    }

}

...

error:

clean up the mess

²  跳轉的標號必須單獨在一行的最左邊。Goto語句需要有相應的註釋,說明它的用途。

2.9.2.    Continue and Break

²  Continue 和break 實際上起到與goto一樣的作用,因此,儘量少用爲上。並且,Continue與break最好不要連用。

2.9.3.    ?:

²  用括號把條件表達式括起來。

²  不要在 ? : 中寫上過多的代碼,操作表達式應儘可能簡潔。

²  操作語句應分行寫,除非它們能夠簡潔的放在一行當中。

例如:

   (condition) ?funct1() : func2();

   或

   (condition)

      ? longstatement

      : anotherlong statement;

2.10.   運算符號的規則 (適用於C/C++)

²  一元操作符如(!、~ 等等)應貼近操作對象。

如:

if (!IsOk)

return ++v;

²  二元操作符如(+、*、%、== 等等)應在前後留空格。

如:

if ( v1 == v2)

     return v1 * 3;

²  ++ 和 -- 儘量使用前置運算。在C++中,不管 ++i 還是 i++,總是++i更容易生成優化代碼。

如:

for(int i = 0; i < 10; ++i)

2.11.    變量聲明語句塊 (適用於C/C++)

²  變量應該是隨用隨聲明,不要集中在函數前(有些C語言不支持,則不在此要求之列)。特別是在for語句的循環變量,應只在for語句中定義。

如:

for(int i = 0; i < 10; ++i)

²  聲明語句塊必須要對齊

類型,變量,等號和初始化值要分別對齊。

例如:

   DWORD      mDword;

   DWORD*     mpDword;

   char*      mpChar;

   char       mChar;

  mDword     =    0;

   mpDword    =    NULL;

   mpChar      =    NULL;

   mChar      =    0;

3.    文檔及註釋

應當使用文檔自動生成工具,來生成相關的程序文檔。

3.1. 文件或程序庫的文檔註釋(適用於C/C++)

可以爲整個文件編寫文檔。

例如:

/** @file file.h

 * Abrief file description.

 * Amore elaborated file description.

 */

3.2. 類文檔註釋(適用於C/C++)

在類定義前面應加上類說明文檔。

例如:

/** WindowsNT

 *  @brief Windows Nice Try.

 *  @author Bill Gates

 *  @author Several species of small furryanimals gathered together

 *          in a cave and grooving with a pict.

 *  @version 4.0

 

 *  @date   1996-1998

 *  @bug It crashes a lot and requires hugeamounts of memory.

 *  @bug The class introduces the more bugs, thelonger it is used.

 *  @warning This class may explode in your face.

 *  @warning If you inherit anything from thisclass, you're doomed.

 */

class WindowsNT {};

 3.3. 函數文檔註釋(適用於C/C++)

²  函數註釋

所有的參數都應該有文檔說明(param),所有的返回代碼都應該有文檔說明(return),所有的例外都應該有文檔說明(exception)。可以使用(see)引用有關的開發資源。如:

  /**

   * 賦值操作符

   *

   *@param val 將要賦給本對象的值

   *

   *@return 本對象的引用

   */

  XX&  operator =(XX& val);

²  註釋屬性

一些自動文檔工具定義的屬性可以包含在文檔中,常用的有:

n  前提條件 (pre)

定義調用這個函數的前提條件

n  警告說明 (warning)

定義一些關於這個函數必須知道的事情。

n  備註說明 (remarks)

定義一些關於這個函數的備註信息。

n  將要完成的工作 (todo)

說明哪些事情將在不久以後完成

n  使用例子說明 (example)

一個圖片能表達100句話,一個好的例子能解答1000個問題。

例如:

  /**

   * 複製一個字串

   *

   *@pre

   *     - 需要保證(from != 0)

   *     - 需要保證(to != 0)

   *

   *@warning

   * 緩衝區必需足夠大,以便容納的下要拷貝的字串。

   *

   *@example teststrcpy.cpp

   *

   *@param from 要拷貝的字串

   *@param to 用於容納字串的緩衝區

   *@return void

   */

  void  strcpy(constchar* from, char* to);

3.4. Include 語句註釋 (適用於C/C++)

²  如果有必要,#include語句也應有註釋,它可以告訴我們,爲什麼要包含這個頭文件。

3.5.語句塊註釋(適用於C/C++)

²  語句塊的註釋可以用在語句塊的開頭和結束位置:

    // Block1 (meaningful comment about Block1)

    ... some code

    { 

        // Block2 (meaningful comment about Block2)

        ... somecode

    }  // End Block2

}  // End Block1

4.    編碼要求

4.1. 不要忽略編譯器的警告(適用於C/C++)

²  編譯器的警告,通常能夠指示出編碼存在的筆誤或邏輯錯誤。因此,不能輕視編譯器的任何警告。正確的作法是,不允許代碼在編譯時產生任何警告信息。

4.2. 應使用源代碼管理器(適用於C/C++)

²  根據開發規模,選擇合適的源代碼管理器。使用源代碼管理器是非常必要的。

4.3. 固有的類方法成員(適用於C++)

²  默認構造函數(DefaultConstructor)

如果構造函數的所有參數都是可選的,那麼這個構造函數也是默認構造函數。如果沒有定義任何普通構造函數,則編譯將自動生成一個。

²  虛析構函數(Virtual Destructor)

如果一個類可以被繼承,那麼應該使用虛析構函數。如果沒有定義虛析構函數,則編譯器將自動生成一個。

²  拷貝構造函數(Copy Constructor)

如果一個類不應該被拷貝,應該定義一個私有的拷貝構造函數,並且不定義它的實現。如果不知道一個類是否應該被拷貝,就認爲它是不可拷貝的,直到你確認它應該被拷貝。如果沒有定義拷貝構造函數,則編譯器將自動生成一個。

 

²  賦值操作(AssignmentOperator)

如果一個類不應該被賦值,應該定義一個私有的賦值操作函數,並且不定義它的實現。如果不知道一個類是否應該被賦值,就認爲它是不可賦值的,直到你確認它應該被賦值。如果沒有定義賦值操作函數,則編譯器將自動生成一個。

4.4. 使用命名空間 (適用於C++)

²  命名規則

根名字一般是設計者的名字。比如公司名稱等等。

²  不要在全局空間使用using語句。

4.5. 初始化所有的變量 (適用於C/C++)

²  無論如何,都要初始化所有的變量。我們無法保證編譯器會給個什麼樣的初值。

4.6. 保持函數短小精悍(適用於C/C++)

²  一般情況下,一個函數最好在一個屏幕內,不要超過三個屏幕。

4.7.對空語句進行註釋 (適用於C/C++)

²  For和while語句如果跟隨一個空語句,需要對此語句進行註釋,並且空語句應另起一行。如:

   while(*dest++ = *src++)

      ;         // VOID

²  不允許寫成:

   while (*dest++ = *src++) ;   // 絕對不允許這麼寫

4.8. 不要用if語句的默認方法測試非零值(適用於C/C++)

²  If語句只用於檢測布爾值(bool),不要用默認的方法測試非零值,比如:

建議使用:

   if (FAIL != f())

不建議使用下面的表達式:

   if (f())

²  宏定義的情況也一樣:

   #define STREQ(a,b) (strcmp((a), (b)) == 0)

或者使用內聯函數:

   inline bool

  StringEqual(char* a, char* b)

   {

      (strcmp(a, b)== 0) ? return true : return false;

       Or more compactly:

      returnstrcmp(a, b) == 0;

   }

4.9.布爾類型 (適用於C/C++)

²  早期的C++沒有布爾類型,但新的C++標準增加了布爾類型。如果可以使用內置的布爾類型的情況下,應使用布爾類型。

早期的布爾類型定義爲:

   typedef int     bool;

   #defineTRUE    1

   #defineFALSE   0

或:

   const intTRUE  = 1;

   const int FALSE= 0;

²  在這種情況下,條件表達式不要比較1值(如TRUE,YES等等),而要用0值(如FALSE,NO等等)進行比較。因爲多數函數返回0表示FALSE,而非零表示TRUE。如:

   if (TRUE ==func()) { ... // 錯誤:假如func()返回 2 怎麼辦?

必須寫成:

   if (FALSE !=func()) { ...

4.10.   避免在語句中內含賦值 (適用於C/C++)

²  只有一種情況可以在語句中內含賦值,它要能使代碼顯得更易理解,例如:

   while (EOF != (c= getchar()))

   {

      process thecharacter

   }

²  ++ 和 -- 操作也是一種賦值語句

²  內含賦值語句常常會帶來一些副作用。在遇到這種情況時,我們應分成幾個語句來寫。比如:

   a = b + c;

   d = a + r;

不應該寫成:

   d = (a = b + c)+ r;

4.11.   正確的使用Const (適用於C/C++)

²  C/C++ 提供const 關鍵字,用於指示不應該被修改的對象或數據。正確的使用Const既可以提供編譯器的優化指示,也能夠避免一些編碼錯誤。

4.12.    不要在頭文件定義數據(適用於C/C++)

不要把數據定義放在頭文件,如:

/*

 * aheader.h

 */

int x = 0;

4.13.   不要直接使用數字 (適用於C/C++)

²  直接使用數字,會使源代碼難以理解和維護。如:

if      (22 ==foo)    { start_thermo_nuclear_war(); }

else if (19 == foo)    {refund_lotso_money(); }

else if (16 == foo)    {infinite_loop(); }

else                   { cry_cause_im_lost(); }

當一段時間過去以後,有誰會記得22和19是什麼意思?假如數字改變,或者是編寫錯誤,更是難以發現問題。

²  我們可以用#define或者常量來改變這一狀況,如:

#define  PRESIDENT_WENT_CRAZY  (22)

const int WE_GOOFED= 19;

enum

{

    THEY_DIDNT_PAY=16

};

if (PRESIDENT_WENT_CRAZY    == foo) { start_thermo_nuclear_war(); }

else if (WE_GOOFED          == foo)  {refund_lotso_money(); }

else if (THEY_DIDNT_PAY     == foo) { infinite_loop();}

else                                 {happy_days_i_know_why_im_here(); }

4.14.    宏(適用於C/C++)

²  如果可以,使用內聯函數代替宏。

例如:

#ifndef MAX

#define  MAX(x,y)  (((x) > (y) ? (x) : (y))    // 取最大數

#endif

使用內聯函數可以達到相同的效果,而且更安全:

   inline int

   max(int x, inty)

   {

      return (x> y ? x : y);

   }

²  要注意副作用

必須小心副作用,因爲在調用表達式時,會發生潛在的錯誤。

例如:

   MAX(f(x),z++);

²  表達式總是用括號括起來

在宏展開時,使用括號可以避免宏展開後產生的二義性。

例如:

#define ADD(x,y) x + y

必須寫成:

#define ADD(x,y) ((x) + (y))

²  保證宏名稱的唯一性

和全局變量一樣,宏也會與其它名稱產生衝突。下面兩條規則有助於解決這個問題:

n  在宏名稱前加上庫的名字

避免使用簡單而常用的名字,如:MAX 和MIN。

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章