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);
/** @}*/ // 文件操作函数
/** @}*/ // 自动注释文档范例