专业化的程式设计之Coding Rules谈
郑力群 ·yesky
前言:
要开发出专业化的软件产品,在编码阶段,必须严格贯彻一定的代码开发准则,这会减少程式的隐含错误,同时使程式的内部结构清晰。从而开发出少错误、易维护的优质程式,使得程式的团队合作性和专业化程度大为提高。这是软件开发中公认的一个准则,也是软件工程在编码阶段的一个具体的应用。我曾与不少编程的朋友讨论过这个问题,在实际的开发中也积累了一些心得,现在我将我所体会到的Coding Rule整理于下:
内容:
适用平台为32位Windows,语言为以C++为基础的语言(C++,VC++...)
一.提高程序的可读性要求:
1.对你所写的每一个文件都加上相关的标准化注释,一般应包括:文件的作用、版本号信息、作者及时间等。
2.为你定义的类写详细的注释,包括作者、时间、版本修订信息、基本的算法、以及成员变量的详细解释等。
3.为你定义的每一个函数写详细的注释,包括输入输出参数说明、返回值说明、函数功能说明。
********************************************************************************
4.在函数的内部,长条注释(划分功能模块)、短条注释(说明实现的各步骤)与句后解释(说明重要句的意义)相结合,清晰功能的实现层次。
file://*************下面实现如下功能 *****************
file://进行...操作(1)。
..............
.............. file://此操作作用为...。
file://进行...操作(2)。
5.所有命名(类、函数、变量..)均要求意义明确易于理解。
6.避免在代码中直接使用数字和TRUE/FALSE等不确定意义的词,尽量使用有意义的串值代替。
const static WORD W_PERSON_NUM = 10;
BOOL bMustProcess = TRUE;
7.最好不要出现向“if(test)等”逻辑判断语句,用以下代替:
if( TRUE == test)
if( PersonNum == test)
if(NULL != test).
8.不要使用goto。
9.不要写太长的if(){...},for(){...},While(...){}或者太多的嵌套。
10.对上述较长者在范围结束处加注释。如//for 循环结束
11.在名字上区分各种变量及函数
类成员变量:m_*,全局变量:g_*,API函数:::。
二.消除程序中的隐患
降低耦合性:
1.只有被其他类引用的函数才定义成public型函数。
2.类中最好不用public型成员变量(经典代替方法:为这个变量写Get与Set函数)。
3.最好不使用全局变量。
说明:可以在C*App类中指定,然后使用AfxGetApp()->***来使用
提高聚合性:
1.一个公用的成员函数不可返回所在类的成员变量的指针或非常量的引用。
2.使用一个类,在可能的情况下(仅通过指针或引用被访问的类),应将类的头文件包含在使用者的.cpp文件中,提高封装性,同时避免重复包含(类为自定的情况下)。如果必须在使用者的.h文件中包含此类的头文件,应使用ifdef...语句避免重复包含。
3.函数的功能应单一,参数的意义应该单一。
基本规则:
1.尽量使用括号来清晰计算表达式的顺序。
2.使用引用参数来代替指针参数(明晰语义;保证传递时已经初始化了;保持效率)。
3.变量定义时应赋初值。
4.使用NULL == *,FALSE == *,代替 * == NULL,* ==FALSE...。
说明:避免笔误
5.使用NULL;空语句。
While(---)NULL; file://避免笔误(误加分号)
6.使用const static 代替 #define(使用编译器的类型检查机制)。
7.所有含虚函数的类的析构函数必须是虚析构函数。
8.在VC下编程时,设置编译选项“Warning level”为“Level 4”(启动编译器所有的预警功能)。
9.函数中自己编制的return前,最好应用系统默认值。
10. debug版与Release版。
#ifdef DEBUG #define DEBUG
......
.....
#endif#undef DEBUG
11. 反安装时,应移去所有我们自定义的DLL,LIB,OCX,注册表项...。
内存相关问题:
1.在分配内存(如图形结构...)时,应该先使用Memset(..)等函数赋值内 存。 Exm1:
BITMAP bm;
::memeset(&bm,0,sizeof(BITMAP));
Exm2:
TCHAR tszName[MAX_PATH];
::memeset(tszName,0,sizeof(TCHAR) * MAX_PATH);
2.所有涉及到内存分配的地方一定要判断是否分配成功,并进行相应的处理。
3.使用 new 与 delete 来分配和释放堆内存(更安全;易测试内存泄漏)。
4.指针问题:
定义Pointer时:将Pointer初始化置空NULL(原因:否则if( NULL == *)会失效)。
任何时候使用Pointer时,均先判断它是否为空,为空则应相应处理。
分配内存前,先判断是否非空,为非空先删去置空。
分配内存后,马上判断是否分配成功(Pointer!=NULL),为空则相应处理。
释放指针时,判断是否非空,非空则先删去(delete),再置空(原因:只有置空的指针使用delete时会不做任何事)。
5.程式设计完成后,使用debug检查是否有内存泄漏;利用资源监视器一类的软件分析程式中是否有全局或局部未释放的内存。
三.共同约定,统一形式,方便多人合作(大多数为目前通用的约定)。
1.定义结构:
typedef struct tagSTRUCTNAME
{
....
}STRUCTNAME ;
2.定义常量:
const static WORD W_PERSON_NUM = 10;
3.命名规则:
XX
前缀
xx
前缀
类class
C
bool->BOOL
b
成员变量
m_
BYTE
by
全局变量
g_
char->TCHAR
tch
API函数
::
WORD
w
指针
p/lp
DWORD
dw
句柄
h
int->LONG
l
LPTSTR
lpsz
float
f
LPCTSTR
lpcsz
DOUBLE
db
POINT
Pt(diff for p)
RECT
rt