开发管理之代码编码规范.docx
《开发管理之代码编码规范.docx》由会员分享,可在线阅读,更多相关《开发管理之代码编码规范.docx(13页珍藏版)》请在冰豆网上搜索。
开发管理之代码编码规范
1.程序版式
1.1.对齐
1.1.1.程序块要采用缩进风格编写,缩进的空格数为4个。
使用VC提供的Tab键对齐。
1.1.2.“{”和“}”应独占一行并且位于同一列,同时引用他们的语句对齐
1.1.3.{}之内的代码块在“{”右边数格外左对齐
例:
正确错误
voidFunction(intx)
{
…
1.1.4.,“;”,“)”向前紧跟
1.1.5.“,”后要留空格,“”;之后如果不是一行的结束,后面要留空格
1.1.6.赋值操作符,比较,算术,逻辑,第二元操作符前后加空格
1.1.7.一元操作符!
、~、++、--、—等前后不加空格
1.1.8.像[]、“.”、—>等前后不加空格
例:
voidFunc1(intx,inty,intz);
Function();
b->Function();
1.1.1.
从左至右
!
~++--(类型)sizeof
+-*&
从右至左
*/%
从左至右
+-
从左至右
<<>>
从左至右
<<=>>=
从左至右
==!
=
从左至右
&
从左至右
^
从左至右
|
从左至右
&&
从左至右
||
从右至左
:
从右至左
=+=-=*=/=%=&=^=
|=<<=>>=
从左至右
1.1.2.if语句
1.1.2.1.布尔变量与零值比较时,不可将布尔变量直接与TRUE、FALSE或者1、0进行比较
假设布尔变量名字为flag,它与零值比较的标准if语句如下:
if(flag)
1.1.3.中,不需要对外公开的常量放在定义文件(*.cpp)的头部
1.1.4.不能在类中初始化const常量,只能通过枚举常量来解决
例:
错误:
classA
{
constintSIZE=100;(错误)
intarray[SIZE];
}
正确:
classA
{…
enum{SIZE1=100,SIZE2=200};//枚举常量
intarray1[SIZE1];
intarray2[SIZE2];
};
1.2.函数
1.2.1.参数规则
1.2.1.1.参数书写要完整,不能只写类型,不写参数名,如果函数没有参数,用void填充
例如:
voidSetValue(intwidth,intheight);//良好的风格
voidSetValue(int,int);//不良的风格
floatGetValue(void);//良好的风格
floatGetValue();//不良的风格
1.2.1.2.如果参数是指针,且仅作输入用,则应在类型前加const,以免指针在函数体内被意外修改;一般地,应将目的参数放在前面,源参数放在后面
例:
voidStrngCopy(char*strlDestintion,consthar*StrSource)
1.2.1.3.如果参数以值传递的方式传递对象,则宜改用“const&”方法传递,能提高效率
1.2.1.4.避免函数有太多的参数,参数个数应尽量控制在5个以内
1.2.1.5.尽量不要使用类型和数目不确定的参数
例:
intprintf(constcha*format[,argument]…);
1.2.1.6.对于内置类型参数要传值
1.2.1.7.需要传指针不传引用的情形
a)内部需要用NULL状态(引用没有NULL状态)
b)若参数是被new出来的,是将在函数内被释放
1.2.2.返回值规则
1.2.2.1.函数的输出值结果用输出参数(一般为指针)获得,状态用return返回
1.2.2.2.如果返回一个对象,一般用引用传递,但有的情况下必须用值传递
例如:
classString
{
…
//赋值函数
String&operate=(constString&other);
//相加函数,如果没有friend修饰则只许有一个右侧参数
friendStringoperate+(constString&s1,constString&s2);
private:
char*m_data;
}
String的赋值函数operate=的实现如下:
String&String:
:
operate=(constString&other)
{
if(this==&other)
{
return*this;
}
deletem_data;
m_data=newchar[strlen+1];
strcpy(m_data,;
return*this;//返回的是*this的引用,无需拷贝过程
}
对于赋值函数,应当用“引用传递”的方式返回String对象。
如果用“值传递”的方式,虽然功能仍然正确,但由于return语句要把*this拷贝到保存返回值的外部存储单元之中,增加了不必要的开销,降低了赋值函数的效率。
例如:
Stringa,b,c;
…
a=b;//如果用“值传递”,将产生一次*this拷贝
a=b=c;//如果用“值传递”,将产生两次*this拷贝
String的相加函数operate+的实现如下:
Stringoperate+(constString&s1,constString&s2)
{
Stringtemp;
delete;//是仅含‘\0’的字符串
=newchar[strlen+strlen+1];
strcpy,;
strcat,;
returntemp;
}
对于相加函数,应当用“值传递”的方式返回String对象。
如果改用“引用传递”,那么函数返回值是一个指向局部对象temp的“引用”。
由于temp在函数结束时被自动销毁,将导致返回的“引用”无效。
例如:
c=a+b;
此时a+b并不返回期望值,c什么也得不到,流下了隐患。
1.2.2.3.尽量保持函数只有唯一出口
1.2.2.4.若函数返回状态,尝试用枚举作类型
1.2.2.5.当函数返回引用或指针时,用文字描述其有效性
1.2.2.6.禁止成员函数返回成员的引用或指针
1.2.3.函数内部规则
1.2.3.1.在函数体的“入口处”,对参数的有效性进行检查,应正确使用断言(assert),断言assert是仅在Debug版本起作用的宏,它用于检查“不应该”发生的情况
例:
void*memcpy(void*pvTo,constvoid*pvFrom,size_tsize)
{
assert((pvTo!
=NULL)&&(pvFrom!
=NULL));//使用断言
byte*pbTo=(byte*)pvTo;//防止改变pvTo的地址
byte*pbFrom=(byte*)pvFrom;//防止改变pvFrom的地址
while(size-->0)
*pbTo++=*pbFrom++;
returnpvTo;
}
1.2.3.2.在函数的“出口处”,应对return语句的正确性和效率进行检查
1.2.3.3.return语句不可返回指向“找内存”(内部变量)的指针或引用,因为该内存在函数体结束时被自动销毁
1.2.3.4.要搞清楚返回的究竟是值、指针,还是引用
1.2.3.5.如果函数返回值是一个对象,要考虑return语句的效率
1.2.4.通用规则
1.2.4.1.函数的功能要单一,不要设计多用途函数
1.2.4.2.函数体规模要小,尽量控制在100行代码以内,不包括注释和空格行
1.2.4.3.尽量避免函数带有记忆功能,相同的输入应当产生相同的输出(不用static变量)
示例:
如下函数,其返回值(即功能)是不可预测的。
unsignedintinteger_sum(unsignedintbase)
{
unsignedintindex;
staticunsignedintsum=0;//注意,是static类型的。
//若改为auto类型,则函数即变为可预测。
for(index=1;index<=base;index++)
{
sum+=index;
}
returnsum;
}
1.2.4.4.用于出错处理的返回值一定要清楚
1.2.4.5.引用的规则
a)引用被创建时同时被初始化
b)不能有NULL引用,引用必须与合法的存储单元关联
c)一旦引用被初始化,就不能改变引用的关系
d)引用的功能主要是传递参数和返回值
C++语言中,函数的参数和返回值的传递方式有三种:
值传递、指针传递和引用传递。
以下是“值传递”的示例程序。
由于Func1函数体内的x是外部变量n的一份拷贝,改变x的值不会影响n,所以n的值仍然是0。
voidFunc1(intx)
{
x=x+10;
}
…
intn=0;
Func1(n);
cout<<“n=”<以下是“指针传递”的示例程序。
由于Func2函数体内的x是指向外部变量n的指针,改变该指针的内容将导致n的值改变,所以n的值成为10。
voidFunc2(int*x)
{
(*x)=(*x)+10;
}
…
intn=0;
Func2(&n);
cout<<“n=”<以下是“引用传递”的示例程序。
由于Func3函数体内的x是外部变量n的引用,x和n是同一个东西,改变x等于改变n,所以n的值成为10。
voidFunc3(int&x)
{
x=x+10;
}
…
intn=0;
Func3(n);
cout<<“n=”<对比上述三个示例程序,会发现“引用传递”的性质象“指针传递”,而书写方式象“值传递”。
实际上“引用”可以做的任何事情“指针”也都能够做,为什么还要“引用”这东西
答案是“用适当的工具做恰如其分的工作”。
指针能够毫无约束地操作内存中的如何东西,尽管指针功能强大,但是非常危险。
就象一把刀,它可以用来砍树、裁纸、修指甲、理发等等,谁敢这样用
如果的确只需要借用一下某个对象的“别名”,那么就用“引用”,而不要用“指针”,以免发生意外。
比如说,某人需要一份证明,本来在文件上盖上公章的印子就行了,如果把取公章的钥匙交给他,那么他就获得了不该有的权利。
2.内存管理
2.1.内存分配方式
有三种分配方式
(1)静态存储区分配,内存在编译的时候已经分配好,这块内存在整个运行期间都存在,例如全局变量,static变量
(2)在栈上创建,执行函数时,函数内部局部变量都在栈上创建,函数执行结束时,这些存储变量自动被释放
(3)从堆上分配,亦称动态内存分配,程序运行时用malloc或new申请任意多少的内存,程序员自己负责在何时用free或delete释放内存
2.2.常见的内存错误
(1)内存分配未成功,却使用了它。
对于函数参数,用asset(p!
=NULL)检查,如果是malloc或new来申请内存,应用if(p==NULL)或if(!
p==NULL)来处理
(2)内存分配虽然成功,但是尚未初始化就引用它,内存的默认值并不一定为空
(3)内存分配成功,也初始化了,但越界了
(4)忘记了释放内存,造成内存泄漏释放了内存却继续使用它
2.3.规则
(1)用malloc或new申请内存后,应立即检查指会值是否为NULL,防止使用指针值为NULL的内存
(2)不要忘记为数组和动脉内存赋值,防止将未被初始化的内存作为右值使用
(3)防止数组或指针的下标越界
(4)动态内存的申请与释放必须配对,防止内存泄漏
(5)用free或delete释放内存之后,立即将指针设置为NULL,防止产生“野指针”
野指针的三种来源:
A.指针变量被创建时没有初化
B.指针被free或delete后没有被赋NULL
C.指针不在有效期
(6)用new创建动态数组,必须用delete[],如:
obj*objects=newobj[100];
delete[]objects;
(7)用new,delete代替malloc、calloc和free
3.MFC控件的命名规则
CButtonm_btnValue
CComboBoxm_cmboValue;
CDialogCDlgServerstatus;
CDateTimeCtrlm_dtcValue;
CEditm_editValue;
CListBoxm_lsbValue;
CListCtrlm_lscValue;
COleDateTimem_dtValue;
CProgressCtrlm_prgValue;
CRichEditCtrlm_reditValue;
CScrollBarm_scrValue;
CSliderCtrlm_slidValue;
CStaticm_staValue;
CTabCtrlm_tabValue;
CTreeCtrlm_treeValue;
4.MFC资源的命名规则
4.1.Dialog
第一级:
IDD_MAIN_QUERY
第二级:
IDD_QUERY_MULTI
第三级:
IDD_QUERY_MULTI_CONFIG
4.2.Menu
IDM_FILTER
4.3.ToolBar
IDT_QUERY
4.4.Cursor
IDC_ZOOM
4.5.Bitmap
IDB_LOGO_CY
4.6.Icon
IDI_LEFT