年后将开始本年度最重要的产品开发,而且在性能方面要求很高,希望通过这款网络产品打开大流量网络安全审计的市场。所以年前一直在做系统分析、系统设计、技术调研,我自己也要制定C++组的C++开发编码规范。
以前4年多来,一直是开发人员想怎么写就怎么写,所以10万行代码里什么风格都有,unix风格, mfc风格, java风格,大小写、下划杠分隔,乱得很,所以这次很有必要统一规范一下;当然这个规范没办法采用单一的风格,只有看老代码里最多的使用的那种了,然后来个大杂烩,不然老员工不接受。
总之,不管什么风格,只要所有开发人员能统一了就是好的。
采用全小写,多个单词之间直接连接。由于文件夹数量相对比较少,我们使用一两个单词就可以表达清楚,所以这种命名方式足够了。
名称一般要体现名词性。
例如:
framework、webwatch、yahoohttp、chat163、msnudpfile
采用每个单词首字母大写,单词其余部分全小写,多个单词之间直接连接;只有一个单词,首字母也要大写。
名称一般要体现名词性。
例如:
Chat.h、Chat.cpp、
CommandParser.h、CommandParser.cpp、
DBQueryPool.h、 DBQueryPool.cpp、
TcpSessionList.h、TcpSessionList.cpp
类名:采用每个单词首字母大写,单词其余部分全小写,多个单词之间直接连接;只有一个单词,首字母也要大写。(与文件名命名相同)
名称一般要体现名词性。
例如:
class Chat {…};class LineReader {…};
class CommandParser {…};class DBQueryPool {…};
成员函数名:采用首单词全小写,其余单词首字母大写,多个单词之间直接连接;只有一个单词,全小写。
名称一般要体现动词性,单个动词或动宾结构。
例如:
class LineReader
{
public:
int push(void * buf, int size);
int getLine(void * buf, int size);
int getLineLen();
private:
void moveData(int copyLen);
private:
int _count;
int _bufIndex;
int _bufSize;
char * _pBuf;
};
成员变量名:以下划杠开头, 之后部分和成员函数名命名方式一样。例子参见上面代码片段。
名称一般要体现名词性。
与1.3类名命名相同。
名称一般要体现名词性。
例如:
typedef struct DataTrunk
{
unsigned int _type;
char _data[256];
void * _pData;
struct DataTrunk * _pNext;
} DataTrunk;
枚举名:与1.3类名命名相同。
成员名:所有字母大写,各单词之间用下划杠分隔。
名称一般要体现名词性。
例如:
enum DataTrunkType
{
ETHER_PKG = 0,
IP_PKG = 1,
UDP_PKG = 2,
TCP_PKG = 3,
MSG_STARTUP = 4,
MSG_SHUTDOWN = 5,
MSG_LOAD = 6,
MSG_UNLOAD = 7,
TCP_STREAM = 8
};
所有字母大写,各单词之间用下划杠分隔。
名称一般要体现名词性。
例如:
#define IPCHAIN_SIZE 64
#define PACKDIR_OUT 0
#define PACKDIR_IN 1
#define PACKDIR_OTHER 2
所有字母小写,各单词之间用下划杠分隔。
名称一般要体现动宾结构。
例如:
int init_db_pool();
void parse_mail(char * data, string & from);
所有字母小写,各单词之间用下划杠分隔。
名称一般要体现动宾结构。
记住需要添加static关键字。
例如:
static void process_db_pool();
全局变量:以小写g开头。例如:
int gPoolSize = 0;
char gHostName[128] = {0};
局部静态变量:以小写s开头。例如:
static int sLoopCount = 0;
static char sBlackList[256] = {0};
指针类型变量:以小写p开头。例如;
char * pBuf = NULL;
int * pBufLen = NULL;
char * _pBuf; // 类成员变量
char * gpHostName = NULL; // 全局的指针类型
static int * spLoopCount = 0; // 静态的指针类型
l 代码行长度:
鉴于我们现有的显示器屏幕高度在45~65行之间,而宽度在100列左右。
一个函数体,代码行数原则上控制在40行以内,最多不要超过80行,也就是在vim编辑器里,大多数函数不用翻屏就能看完,少数函数最多也就上下翻动一屏,以提高可读性。
而一行代码,最长不能超过90列,超过了就应该手工分行。
注意:函数体应该是一个高内聚的功能体,我们首先应该从它所表达的功能单元来考虑提取一个函数,函数名应该明确表达其实现的功能;而死死数代码行数,以为在80行以内就是好函数,这是错误的。
建议:类成员函数应该短一些,控制在40行以内;而全局函数和局部静态函数,相对于类成员函数,代码行可以长一点。
l 函数参数命名:
采用首单词全小写,其余单词首字母大写,多个单词之间直接连接;只有一个单词,全小写。
int readLine(void * pBuf, bool allwaysReturn);
l 函数体内变量命名:
如果函数体控制在适当大小,功能高内聚,那么我们不需要定义太多局部变量,所以临时变量可以采用简单的单词来命名,全部小写,如果实在比较长,则采用首单词全小写,其余单词首字母大写,多个单词之间直接连接。
例如:
int i = 0;
int len = 0;
bool flag = true;
int tcpport = 80;
char * pName = NULL;
l 花括号对齐:
int parse_mail( )
{
if( … )
{
}
return 0;
}
l 代码行缩进:
代码行要按通常模式缩进,必须使用tab来缩进;千万不要使用敲空格来缩进。因为在用编辑器来阅读时,有人习惯2列缩进,而有人习惯4列缩进,他们可以自己设置自己喜欢的缩进方式,动态处理tab的显示效果,如果用敲空格来缩进,就固定死了。例如在.vimrc里设置:
set shiftwidth=4
set tabstop=4
而有些人可能设置:
set shiftwidth=2
set tabstop=2
不要设计一个功能大而全的类。
类公共接口数控制在8个以内。(贝尔实验室研究错误率后建议的数量,<<重构>>作者Martin Fowler建议的数量)
在明确需要提供拷贝构造函数和赋值构造函数时,一定要实现,比如成员变量有指针,并在构造函数里分配而在析构函数里释放了动态内存时;如果不想提供,则可以明确private化,以免误用值传递。
l 头文件:
一定要有预编译宏:
#ifndef _SESSION_MANAGER_H_
#define _SESSION_MANAGER_H_
//这里声明你的全局函数、类等
#endif//_SESSION_MANAGER_H_
类、结构体、枚举要有功能说明。
全局函数、public型成员函数要有功能说明,最好添加参数说明和返回值说明,而private型则可有可无。
函数头的说明,建议采用doxygen格式编写,以后可以使用doxygen来自动生成说明文档。
/*
* 打开文件
* @param [in] pFileName 文件名
* @param [in] mode 打开模式: 0-读,1-写,2-读写
* @return 0—成功,-1—失败
*/
int open_file(const char * pFileName, int mode);
l 源文件:
不要乱引用头文件,只保留应该引用的头文件,以减少依赖,加快编译速度。
文件行数最多不要超过500行。因为平均一个函数控制在50行的话,一个文件里写10左右的函数就够多了,用vim上下翻动10屏以上是很辛苦的。