编程规范
工作中整理的规范,把在自己总结的必须要的规范列了出来,其他的一些可有可以无的全不要,以达到精简,毕竟工作的时间还是不要浪费到不是特别重要的事情上。
一、 命名约定(C++)
变量使用“匈牙利式”命名约定,变量名加对应的前缀,后加上一个以大写字母开头的 “标签”。szTo、nLength、dwCount、m_nLevel、g_nIndex。
a) 变量名前添加对应的类型。如:
char ch; /* 所有的字符变量均以ch开始 */
byte b; /* 所有的字节均冠以b */
long n; /* 所有的长字均冠以n */
DWORD dw; /* 所有的DWORD类型均冠以dw */
b) 指向某个数据类型的指针,加上前缀字母P。如:
char* pch; /* 指向ch的指针以p开始 */
byte* pb; /* 同理 */
void* pv; /* 特意显用的空指针 */
char** ppch; /* 指向字符指针的指针 */
byte** ppb; /* 指向字节指针的指针 */
c) 以NULL结束的字符数组,加上前缀sz。如:
char szTo[10]; /* 所有以NULL结束的字符数组前加sz */
wchar_t szFrom[10]; /*所有以NULL结束的宽字符数组前加sz */
d) 字符串变量,加上前缀str。如:
string strTo; /* 所有字符串变量冠以str */
e) 类成员变量,加上前缀m_。如:
long m_n; /* 所有的类变量均冠以m_ */
f) 全局变量,加上前缀g_。如:
long g_n; /* 所有的全局变量均冠以g_ */
二、 使用断言
对于程序中假定成立的条件都要使用断言。
测试时使用调试版来排除这种假定出错的问题。
a) 使用断言对函数参数进行确认。如:
void memcpy(void* pvTo, void* pvFrom, size_t size)
{
void* pbTo = (byte*)pvTo;
void* pbFrom = (byte*)pvFrom;
/* 程序假定参数pvTo、pvFrom非空,则必须使用断言来确认 */
ASSERT(pvTo != NULL && pvFrom != NULL);
/* 程序假定参数pvTo、pvFrom非重叠,则必须使用断言来确认 */
ASSERT(pbTo>=pbFrom+size || pbFrom>=pbTo+size);
while(size-->0)
*pbTo++ == *pbFrom++;
return(pvTo);
}
b) 详细说明不清楚的断言,对于不常用假定的断言需要添加注释。
如:ASSERT(pbTo>=pbFrom+size || pbFrom>=pbTo+size);
c) 不要使用断言去检测真正的错误,而不是非法的情况。如:
char* strdup(char* str)
{
char* strNew;
/* 这个断言是正确的 */
ASSERT(str != NULL);
strNew = (char*)malloc(strlen(str)+1);
/* 这个断言的用法错误,它所测试的是错误情况 */
ASSERT(strNew != NULL);
strcpy(strNew, str);
return(strNew);
}
d) 消除所做的隐式假定,利用断言检查其正确性。
如:使用一个假定初始化过的指针变量
ASSERT(NULL!=m_pA);
m_pA->A();
e) 不要把发布版本需要执行的代码写的断言里面。如:
ASSERT(NULL!=m_pA && m_pA->A()); /* 这里m_pA->A()发布版需要执行的,不能放到断言中 */
三、 代码日志
出日志用于定位程序出错的位置和错误原因,测试时要检查自己编写的代码日志出的是否正确。具体出日志方法见附录。
1、运行时日志:
a) 函数的入口要出INFO日志。如:
LOG_RUNTIME_INFO(EELC_CM,_T("PolicyParse"));
b) 函数中调用其他函数返回异常值要出ERROR日志。如:
LOG_RUNTIMEF((EELL_ERROR, EELC_CM, _T("Failed to open file: %s,%08x"), lpszFilePath, GetLastError()));
c) 函数中异常处理要出ERROR日志。
d) 公用类、公用函数或循环的代码内不要出日志,在调用的地方出。
e) 需要记录相关变量值或结果值时出DETAILED日志。
f) 对应出现几率比较少的路径出WARING或INFO日志。如:
LOG_RUNTIME_WARING(EELC_CM, _T("The length of the upload file is 0"));
g) 关键函数中出现未知异常,可以出dump。如:
BOOL Server::Start()
{
try
{
…
)
Catch(…)
{
Debug::GenerateMiniDump(NULL, NULL);
LOG_RUNTIME_ERROR(EELC_CM,_T("Failed to run server, an unknown exception occur."));
}
}
四、 编码检查
a) 是否初始化所有全局变量、静态变量、局部变量?
b) 检查使用引用计数的对象,增加和释放引用计数是否正确?
c) 是否用断言证实了函数参数的有效性?
d) 是否用断言证实了函数中使用指针的有效性?
e) 调用其他函数的返回值是否都进行了判断?
f) 函数中异常路径是否需要出了调试日志?
g) 如果调用的函数会抛异常,那是否添加了异常处理?
h) 是否将编译程序的警告都处理了?
i) 代码中是否有未定义的或者无意义的代码?
j) 操作符的优先级是否考虑过?使用正确吗?
k) 有没有难以理解的代码?对它们作解释了没有?
l) 代码是否包含了随机行为?能消除这些行为吗?
m) 是否释放了申请过的存储空间?
n) 是否引用已经释放了的存储空间?
o) 是否编写多种功能集于一身的函数?
p) 调用API所用的字符串类型(A或W)是否和调用版本一致?
q) 编写的代码自己是否测试过?