Sevenjay's Coding Style

From Sevenjay's Wiki

Jump to: navigation, search

一個團隊的編程藝術是非常重要的,以下是我整理歸納的Coding Style,並不只適用於c++,關於原因並不多做說明。

Contents

Header Files

  • All header files should have #define guards to prevent multiple inclusion. The format of the symbol name should be PROJECT>_<PATH>_<FILE>_H_.
#ifndef FOO_BAR_BAZ_H_
#define FOO_BAR_BAZ_H_

...

#endif  // FOO_BAR_BAZ_H_
  • Include statements should be sorted and grouped. Sorted by their hierarchical position in the system with low level files included first. Leave an empty line between groups of include statements.
    1. Current foo.cpp head file. "project/public/foo.h" (若是lib可在不同資料夾public).
    2. C system files. <unistd.h>
    3. C++ system files. <vector>
    4. Other libraries' .h files. "base/basictypes.h"
    5. Your project's other .h files. "project/public/bar.h"
#include "project/public/foo.h"  //Current foo.cpp head file

#include <sys/types.h>
#include <unistd.h>

#include <hash_map>
#include <vector>

#include "base/basictypes.h"
#include "base/commandlineflags.h"
#include "project/public/bar.h"

變數

Name Space

  1. 在 header 檔不使用using namespace,在實作層面才為了便利使用。
  2. 可簡化namespace BP = boost::process;
  3. 使用unnamd namespace替代static xxx來達到 global scope in one file(Compilation Unit) only,static修飾的東西不同,意思也不盡相同,容易混淆。

變數(物件)、函式名稱

  1. 區域變數必全小寫或第一單字小寫開頭: index, salary, is_file_open, isFileOpen
  2. 全域變數加上g開頭: gTime
  3. 全大寫:常數、eunm成員、全域函式、巨集
  4. class, enum, 檔案名稱單字首大寫: CamelCase, Account, TestCase, UIMain.cpp, UI_Main.cpp
  5. enum為複數:Angles, Corners
  6. class成員變數:
    1. private, protect加上m開頭: mName
    2. public: PhoneBook
  7. class成員函式: 動詞(+名詞),純名詞為取得封裝成員。
    1. private, protect首字母必小寫: openFile(), save()
    2. public: OpenFile(), Name()=GetName()
  8. 指標變數:
    1. 區域變數指標: pindex, p_index, pIndex
    2. class成員變數指標: mIndexPtr, mNamePtr, PhoneBookPtr
    3. 全域變數指標: gTimePtr

ps: 大寫感覺不會變動,範圍大;小寫感覺容易變動,範圍小。

避免

  • 其他一律不使用前綴、後綴。物件類別提示不算入前綴的一種,可看需求使用:
Button BTN_SAVE, mBtnSave, gBtnSave, BtnSave, btnSave
Label LB_NAME, mLbName, LbName, lbName
  • Avoid Leading Underscores: 以 underscore 起頭的 identifier 都是保留給 compiler/standard library 實作任意使用的[1]

宣告指標

  • 宣告指標(raw pointer)時,型態+空白+*+空白+名稱,若未立即初始化,務必初始化為NULL。:
   int * p = NULL;    //明確宣告為指標位址變數
   int * p1 = NULL, * p2 = NULL;
  • 使用時,*+名稱為使用內容:
   p=&value;   //位址變數
   *p=0;       //內容
  • 刪除指標之後,以下情況請一律設定為NULL
    1. 後面流程非接右大括號(})
    2. 接右大括號(})但非宣告為local scope指標
bool foo(Object * pObject)
{
    ...
    delete pObject;
    pObject = NULL;
    ...
    ...
    delete pObject;
    delete gClient;
    gClient = NULL;
    return true;
}

註解

Doxygen格式

加入適當的程式註解,依據Doxygen的定義[2],以方便輸出Document以及維護。

註解於程式原始檔開頭

標頭檔為必須,其他可視情況。

/**********************************************************************//**
 * @file	ModemDefine.h
 * @brief	Definition of Modem Service module
 * @date	22 March 2009
 * @version	1.3.11
 *
 * Here are definitons all up and down layers need.
 *
 * @note Basically you do not need to modify this file.
 *		 Only if on different platform, modify the definition IN_platform.
 *************************************************************************/

註解於define

非必要

#define MODEM_SEND_BUFFER DEVICE_OUT_BUFFER ///< must be the same with ComPort
#define MODEM_RECV_BUFFER DEVICE_IN_BUFFER  ///< must be the same with ComPort

註解於類別(class)、結構(struct)、列舉(enum)

結構(struct)、列舉(enum)為非必要

/** 
 * @brief Design to be a libiary of the general Modem
 *
 * Directly use the Modem class or inherit it
 * to creat your own modem, like Modem1xxx.
 *
 * If on different platform, modify the definition in ModemDefine.h.
 */
class Modem
{
....
}

註解於類別、結構、列舉成員

非必要

struct PhonebookEntry
{
	std::string index;  ///< 1
	std::string name;   ///< Tina
	std::string number; ///< 0912345678
	std::string email;
};

註解於(成員)函式

必要

/**
 * @brief Change facility password.
 *
 * Send an AT command "AT+CPWD" series.
 * <pre>
 *	RSSI		dbm
 *	0		-113 dBm or less
 *	1		-111 dBm
 *	2..30	-109... -53 dBm	(x dbm = -109 + ( RSSI - 2 ) * 2)
 *	31		-51 dBm or greater
 *	99		not known or not detectable
 * </pre>
 * @param[in] fac A facility contained by FacSupportedChangePW
 * @param[in] oldpw An old password string
 * @param[in] newpw A new password string
 * @param[out] p_atrsp A response string point
 *
 * @retval MS_OK Success
 * @retval CP_INVALID_HANDLE Invalid com port handle
 * @retval CP_FAIL Using com port Fail
 *
 * @note If response string size > MODEM_RECV_BUFFERSIZE, it only recives
 *       MODEM_RECV_BUFFERSIZE. Then you need to reciver the remainder again.
 * @remarks To change password needs to follow the flow states:
 * @code
 * 	at+clck="sc",1,"0000" <--already done(enable) in UI
 * 	OK
 * 	at+cpin="0000" <--even correct pw will error, so not to do, maybe hardware bug
 * 	OK
 * 	at+cpwd="sc","0000","1111"
 * 	OK
 * @endcode
 *
 * @bug ATE1 will also set at+cmee=0, is it a at command bug?
 * @todo Fix the bug.
 */
int Modem::ChangeFacilityPW(FacSupportedChangePW fac, string oldpw, string newpw, char * p_atrsp)
{
...
}

參數較少可使用@a風格簡化

/**
 * Copies bytes from a source memory area to a destination memory area,
 * where both areas may not overlap.
 * @param[out] dest The memory area to copy to.
 * @param[in]  src  The memory area to copy from.
 * @param[in]  n    The number of bytes to copy.
 */
/**
 * Copies @a n bytes from a source memory area @a src to a destination memory
 * area @a dest, where both areas may not overlap.
 */

邏輯

  1. 使用left hand comparisons: if(365==days)
  2. 使用空行分開程式碼的邏輯區塊

函式名稱與回傳值

回傳值為bool型態時,函式名稱以Is開頭:

   bool IsFun(){}
   if(!IsFun()){}

其他函式名稱不可以Is開頭。

錯誤、意外及狀態回傳處理

  • 盡量在Class內管理資源配置,達到自動式資源釋放,避免新增物件後因Exception而中斷資源釋放。(意即RAII)
  • 盡量用 assert 來確認上層呼叫下層時給的參數(環境)保證。保障安全性,也省去Release重複檢查。Release時出現這種情況就已經是意外了,以exception由上(上)層處理。
     void test(const char* str)
     {
       assert(NULL != str);
       size_t len = strlen(str);
       // ...
     }

使用Smart pointer

  • 以物件方式來管理資源,達到RAII,exception safe的程式,故配置指標時,務必使用Smart pointer
  • 類似new所得的資源一律使用scope_ptr或shared_ptr
  • shared_ptr: create object to be shared or returned outside the scope
  • scope_ptr: create object to be non-copy or in the local scope or in a class scope
  • 從別人來的指標用weak_ptr,不用負責生成跟消滅,注意在multithread是不安全的,必須轉成shared_ptr才能使用

其他原則

縮排

不建議使用tab字元做縮排,不同編輯程式對於tab字元寬度定義不同,請用空白字元做縮排。最好的方法是使編輯器支援tab鍵為4個空白。

參考其他風格


Reference:

  1. Avoid Leading Underscores
  2. Doxygen commands

Memory management in C++

Personal tools