现在的位置: 首页 > 综合 > 正文

C++编码规范

2013年10月01日 ⁄ 综合 ⁄ 共 5716字 ⁄ 字号 评论关闭

1. 代码风格

1.1 空格制表符

不一致的缩进宽度会导致行与行之间的参差不齐,进而严重影响代码的可读性,所以统一使用4字节的空格符号来进行缩进,TAB符号必须替换成空格。

1.2 单行长度

为了能在一屏内看到所有代码,单行代码长度尽量少于80个字节,最长不超过100个字节。如果单行代码长度过长,则对该行代码进行合理分行,以限制单行代码的最大长度。

1.3 函数长度

为了方便代码的阅读,在一屏内完整的阅读一段功能块,单个函数的长度最好是控制在一屏以内,尽量少于40行

1.4 字体选择

编辑器的字体尽量选择等宽字体,优先选择Fixedsys。

1.5 大括号

为了缩减函数有效代码行的长度,增加可读性,左大括号采用紧跟在行末的书写格式,所有右大括号使用单独的一行。
示例:

string url_decode(const string& data){
    if (data.empty())
       return "";

    string decoded;
    decoded.reserve(data.length());

    for (const char * c = data.c_str(); *c; c++) {
        if (*c == '%' && isalnum((c+1)) && isalnum(*(c+2))){
            decoded.append(1, xtoc(*(c+1), *(c+2)));
            c += 2;
        }else{
            decoded.append(1,*c);
        }
    }
    return decoded;
}

1.6 指针和引用位置

声明变量名的时候,指针和引用的符号(* 和 &)统一紧挨变量名左边,声明函数返回值的时候,指针和引用符号紧挨类型的右边。

  int *a;
  int &b;
  int* func();
  int& func2();

2. 命名规范

2.1 类

类的首字符必须大写,如果类中有多个单词,单词的首字符大写。
示例:

class Daemon;
class INIParser;
class PhpArray

类声明时,按照public、protected、private的顺序来声明,函数和成员变量的顺序以函数先成员变量后的顺序存放。
示例:

class Foo{
public:
    Foo(void);
    ~Foo(void);

    int func1(void);
 
private:
    int func2(void);
    int m_param1;
    std::string m_param2;
};

2.2 函数

C风格:函数首字符必须小写,如果函数名中有多个单词,单词之间用"_"分隔。
C++风格:函数首字符小写,如果函数名中有多个单词,单词首字母大写。
示例:

void to_lower(std::string &s);
void trim(std::string &s);

2.3 结构体

枚举(enum)类型的成员全部大写,同一枚举类型使用相同的前缀,多个单词之间使用"_"分隔。
示例:

enum{
    ZONE_INACTIVE = 'N',//未激活
    ZONE_ACTIVE   = 'A',//上架
    ZONE_OFF      = 'O',//下架
    ZONE_REJECT   = 'R',//审核拒绝
    ZONE_DELETE   = 'D',//删除
};

结构体(struct)单词的第一个字母大写。
示例:

struct MD5Context{
    uint32 total[2];
    uint32 state[4];
    uint8  buffer[64];
};

2.4 变量

类成员变量使用"m_"作为前缀。
全局变量使用"g_"作为前缀。
静态变量使用"s_"作为前缀。

静态常量使用大写字母、下划线分割。
示例:

static const int END_OF_CMDLINE_OPTION = -1;

3. 文件结构

3.1 头文件

预处理块格式
为了防止头文件被重复导入,头文件中都会定义该文件的预处理块,预处理块名字前后都加上"_"符号,以示区别。
示例:mocker.h文件的预处理块定义如下

#ifndef __MOCKER_H__
#define __MOCKER_H__

//内容

#endif /*__MOCKER_H__*/

引用文件顺序
引用头文件的顺序以下面的先后顺序来存放:

  1. 当前实现对应的头文件(如Foo.cpp对应的Foo.h,详情如下)
  2. C系统头文件
  3. C++系统头文件
  4. 三方库头文件
  5. 二方库头文件
  6. 当前工程头文件

Foo.cpp中依赖Foo.h的情况下,建议将Foo.h放到首位。这样可以做到每一个头文件都是可被独立编译的,即该头文件本身已包含所有必要的显式依赖,最简单的方法是将其作为第一个 .h 文件 #included 进对应的 .cpp。

头文件引入位置
根据最小依赖原则,头文件的引入如果能放到.cpp文件中,就不应该将头文件的引入放到.h文件中来引入。

3.2 文件组织格式

功能模块/库文件组织格式
功能模块/库文件的组织格式如下所示:

其中:

名称 说明
doc 项目文档
include 声明外部接口的所有头文件和内联定义文件
lib 编译好的二进制库文件,可以按编译器、平台分设子目录
src 所有实现文件和声明内部接口的头文件、内联定义文件。可按功能划分;支持编译器、平台等类别分设子目录
utest 存放测试用代码的目录
rpm 制作rpm用的脚本和spec文件

项目文件组织格式
项目文件的组织格式如下所示:

其中:

名称 说明
bin 项目用到的可执行文件和脚本
conf 项目用到的配置文件
doc 项目文档
lib 编译好的二进制库文件,可以按编译器、平台分设子目录
src 所有实现文件和声明内部接口的头文件、内联定义文件。可按功能划分;支持编译器、平台等类别分设子目录
utest 存放测试用代码的目录
rpm 制作rpm用的脚本和spec文件

4. 注释格式

代码注释采用JavaDoc风格的 Doxygen注释格式,详细内容可以参考文档:
http://www.stack.nl/~dimitri/doxygen/manual.html

PS:注释切忌过度,好的代码即文档

4.1 Doxygen常用语法

4.1.1 模块定义
/**
 * @defgroup 模块名 模块的说明文字
 * @{
 */

… 定义的内容 …

/** @} */ // 模块结尾
4.1.2 分组定义
/**
 * @name 分组说明文字
 * @{
 */

… 定义的内容 …

/** @} */
4.1.3 变量、宏定义、类型定义简要说明
/** 简要说明文字 */
#define FLOAT float

/** @brief 简要说明文字(在前面加 @brief 是标准格式) */
#define MIN_UINT 0

/**
 * 分行的简要说明 \n
 * 这是第二行的简要说明
 */
int b;
4.1.4 函数说明
/**
 * 简要的函数说明文字
 * @param [in]  param1 参数1说明
 * @param [out] param2 参数2说明
 * @return 返回值说明
 */

int func(int param1, int param2);

/**
 * 打开文件 \n
 * 文件打开成功后,必须使用 ::CloseFile 函数关闭。
 * @param[in] file_name 文件名字符串
 * @param[in] file_mode 文件打开模式字符串,可以由以下几个模块组合而成:
 * - r 读取
 * - w 可写
 * - a 添加
 * - t 文本模式(不能与 b 联用)
 * - b 二进制模式(不能与 t 联用)
 * @return 返回文件编号
 * - -1 表示打开文件失败
 * @note 文件打开成功后,必须使用 ::CloseFile 函数关闭
 * @par 示例:
 * @code
 // 用文本只读方式打开文件
 int f = OpenFile(”d:\\test.txt”, “rt”);
 * @endcode
 * @see ::ReadFile ::WriteFile ::CloseFile
 * @deprecated 由于特殊的原因,这个函数可能会在将来的版本中取消。
 */
int OpenFile(const char* file_name, const char* file_mode);
4.1.5 枚举类型定义
/** 枚举常量 */
typedef enum TDayOfWeek{
    SUN = 0, /**< 星期天(注意,要以 “<” 小于号开头) */
    MON = 1, /**< 星期一 */
    TUE = 2, /**< 星期二 */
    WED = 3, /**< 星期三 */
    THU = 4, /**< 星期四 */
    FRI = 5, /**< 星期五 */
    SAT = 6 /**< 星期六 */
}

/** 定义类型 TEnumDayOfWeek */
TEnumDayOfWeek;
4.1.6 项目符号标记
/**
* A list of events:
* - mouse events
* -# mouse move event
* -# mouse click event\n
* More info about the click event.
* -# mouse double click event
* - keyboard events
* -# key down event
* -# key up event
*
* More text here.
*/

结果显示为以下格式:

A list of events:
    * mouse events
         1. mouse move event
         2. mouse click event
            More info about the click event.
         3. mouse double click event
    * keyboard events
         1. key down event
         2. key up event

More text here.

4.2 代码示范

/**
* @defgroup EXAMPLES 自动注释文档范例
* @author minidxer
* @version 1.0
* @date 2007-2008
* @{
*/

/**
* @name 文件名常量
* @{
*/

/** 日志文件名 */
#define LOG_FILENAME “c:\\log\\debug.log”
/** 数据文件名 */
#define DATA_FILENAME “c:\\data\\detail.dat”
/** 存档文件名 */
#define BAK_FILENAME “c:\\data\\backup.dat”

/** @}*/ // 文件名常量

/**
* @name 系统状态常量
* @{
*/

/** 正常状态 */
#define SYS_NORMAL 0
/** 故障状态 */
#define SYS_FAULT 1
/** 警告状态 */
#define SYS_WARNNING 2

/** @}*/ // 系统状态常量

/** 枚举常量 */
typedef enum TDayOfWeek{
    SUN = 0, /**< 星期天(注意,要以 “<” 小于号开头) */
    MON = 1, /**< 星期一 */
    TUE = 2, /**< 星期二 */
    WED = 3, /**< 星期三 */
    THU = 4, /**< 星期四 */
    FRI = 5, /**< 星期五 */
    SAT = 6 /**< 星期六 */
}

/** 定义类型 TEnumDayOfWeek */
TEnumDayOfWeek;

/** 定义类型 PEnumDayOfWeek */
typedef TEnumDayOfWeek* PEnumDayOfWeek;

/** 定义枚举变量 enum1 */
TEnumDayOfWeek enum1;

/** 定义枚举指针变量 enum2 */
PEnumDayOfWeek p_enum2;

/**
* @defgroup FileUtils 文件操作函数
* @{
*/

/**
* 打开文件 \n
* 文件打开成功后,必须使用 ::CloseFile 函数关闭。
* @param[in] file_name 文件名字符串
* @param[in] file_mode 文件打开模式字符串,可以由以下几个模块组合而成:
* - r 读取
* - w 可写
* - a 添加
* - t 文本模式(不能与 b 联用)
* - b 二进制模式(不能与 t 联用)
* @return 返回文件编号
* - -1 表示打开文件失败

* @note 文件打开成功后,必须使用 ::CloseFile 函数关闭
* @par 示例:
* @code
// 用文本只读方式打开文件
int f = OpenFile(”c:\\test.txt”, “rt”);
* @endcode

* @see ::ReadFile ::WriteFile ::CloseFile
* @deprecated 由于特殊的原因,这个函数可能会在将来的版本中取消。
*/
int OpenFile(const char* file_name, const char* file_mode);

/**
* 读取文件
* @param[in] file 文件编号,参见:::OpenFile
* @param[out] buffer 用于存放读取的文件内容
* @param[in] len 需要读取的文件长度
* @return 返回读取文件的长度
* - -1 表示读取文件失败

* @pre \e file 变量必须使用 ::OpenFile 返回值
* @pre \e buffer 不能为 NULL
* @see ::OpenFile ::WriteFile ::CloseFile
*/
int ReadFile(int file, char* buffer, int len);

/**
* 写入文件
* @param[in] file 文件编号,参见:::OpenFile
* @param[in] buffer 用于存放将要写入的文件内容
* @param[in] len 需要写入的文件长度
* @return 返回写入的长度
* - -1 表示写入文件失败

* @pre \e file 变量必须使用 ::OpenFile 返回值
* @see ::OpenFile ::ReadFile ::CloseFile
*/
int WriteFile(int file, const char* buffer, int len);

/**
* 关闭文件
* @param file 文件编号,参见:::OpenFile
* @retval 0 为成功
* @retval -1 表示失败

* @see ::OpenFile ::WriteFile ::ReadFile
* @deprecated 由于特殊的原因,这个函数可能会在将来的版本中取消。
*/
int CloseFile(int file);

/** @}*/ // 文件操作函数

/** @}*/ // 自动注释文档范例

抱歉!评论已关闭.