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__*/
引用文件顺序
引用头文件的顺序以下面的先后顺序来存放:
- 当前实现对应的头文件(如Foo.cpp对应的Foo.h,详情如下)
- C系统头文件
- C++系统头文件
- 三方库头文件
- 二方库头文件
- 当前工程头文件
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); /** @}*/ // 文件操作函数 /** @}*/ // 自动注释文档范例