C++关于编程风格的讨论.docx

上传人:b****6 文档编号:5951872 上传时间:2023-01-02 格式:DOCX 页数:29 大小:28.76KB
下载 相关 举报
C++关于编程风格的讨论.docx_第1页
第1页 / 共29页
C++关于编程风格的讨论.docx_第2页
第2页 / 共29页
C++关于编程风格的讨论.docx_第3页
第3页 / 共29页
C++关于编程风格的讨论.docx_第4页
第4页 / 共29页
C++关于编程风格的讨论.docx_第5页
第5页 / 共29页
点击查看更多>>
下载资源
资源描述

C++关于编程风格的讨论.docx

《C++关于编程风格的讨论.docx》由会员分享,可在线阅读,更多相关《C++关于编程风格的讨论.docx(29页珍藏版)》请在冰豆网上搜索。

C++关于编程风格的讨论.docx

C++关于编程风格的讨论

**软件公司软件开发规范

(试行版)

在公司团队协作开发的情况下,编程时应该强调的一个重要方面是程序的易读性,在保证软件的速度等性能指标能满足用户需求的情况下,能让其他程序员容易读懂你的程序。

一套鲜明的编程风格,可以让协作者、后继者和自己一目了然,在很短的时间内看清程序的结构,理解设计的思路。

大大的提高代码的可读性、可重用性、程序健壮性、可移植性和可维护性。

制定本编程规范的目的是为了提高公司的软件开发效率及所开发的软件的可维护性,提高软件的质量。

本规范由程序风格、命名规则、注释规范、程序健壮性、可移植性、错误处理以及软件的模块化规范等部分组成。

一、程序风格:

1、严格采用阶梯层次组织程序代码:

各层次缩进的分格采用VC的缺省风格,即每层次缩进为4格,括号位于下一行。

要求相匹配的大括号在同一列,对继行则要求再缩进4格。

例如:

voidmain()

{

......

longlI;//循环变量

longlSum;//用来记录和

floatfAvg;//用来求平均值

......

//对数进行累加。

for(lI=0;lI<10;lI++)

{

lSum=lSum+lI;

......}

//求平均值。

fAvg=lSum/10.0;

......

}

2、提示信息字符串的位置

在程序中需要给出的提示字符串,为了支持多种语言的开发,除了一些给调试用的临时信息外,其他所有的提示信息必须定义在资源中。

3、对变量的定义,尽量位于函数的开始位置。

二、命名规则:

1、变量名的命名规则

①、变量的命名规则要求用“匈牙利法则”。

即开头字母用变量的类型,其余部分用变量的英文意思或其英文意思的缩写,尽量避免用中文的拼音,要求单词的第一个字母应大写。

即:

变量名=变量类型+变量的英文意思(或缩写)

对非通用的变量,在定义时加入注释说明,变量定义尽量可能放在函数的开始处。

见下表:

bool(BOOL)用b开头bIsParent

byte(BYTE)用by开头byFlag

short(int)用n开头nStepCount

long(LONG)用l开头lSum

char(CHAR)用c开头cCount

float(FLOAT)用f开头fAvg

double(DOUBLE)用d开头dDeta

void(VOID)用v开头vVariant

unsignedshort(WORD)用w开头wCount

unsignedlong(DWORD)用dw开头dwBroad

HANDLE(HINSTANCE)用h开头hHandle

DWORD用dw开头dwWord

LPCSTR(LPCTSTR)用str开头strString

用0结尾的字符串用sz开头szFileName

对未给出的变量类型要求提出并给出命名建议给技术委员会。

②、指针变量命名的基本原则为:

对一重指针变量的基本原则为:

“p”+变量类型前缀+命名

如一个float*型应该表示为pfStat

对多重指针变量的基本规则为:

二重指针:

“pp”+变量类型前缀+命名

三重指针:

“ppp”+变量类型前缀+命名

......

③、全局变量用g_开头,如一个全局的长型变量定义为g_lFailCount,即:

变量名=g_+变量类型+变量的英文意思(或缩写)

④、静态变量用s_开头,如一个静态的指针变量定义为s_plPerv_Inst,即:

变量名=s_+变量类型+变量的英文意思(或缩写)

⑤、成员变量用m_开头,如一个长型成员变量定义为m_lCount;即:

变量名=m_+变量类型+变量的英文意思(或缩写)

⑥、对枚举类型(enum)中的变量,要求用枚举变量或其缩写做前缀。

并且要求用大写。

如:

enumcmEMDAYS

{

EMDAYS_MONDAY;

EMDAYS_TUESDAY;

……

};

⑦、对struct、union、class变量的命名要求定义的类型用大写。

并要加上前缀,其内部变量的命名规则与变量命名规则一致。

结构一般用S开头

如:

structScmNPoint

{

intnX;//点的X位置

intnY;//点的Y位置

};

联合体一般用U开头

如:

unionUcmLPoint

{

longlX;

longlY;

}

类一般用C开头

如:

classCcmFPoint

{

public:

floatfPoint;

};

对一般的结构应该定义为类模板,为以后的扩展性考虑

如:

template

classCcmTVector3d

{

public:

TYPEx,y,z;

};

⑧、对常量(包括错误的编码)命名,要求常量名用大写,常量名用英文表达其意思。

如:

#defineCM_FILE_NOT_FOUNDCMMAKEHR(0X20B)其中CM表示类别。

⑨、对const的变量要求在变量的命名规则前加入c_,即:

c_+变量命名规则;例如:

constchar*c_szFileName;

2、函数的命名规范:

函数的命名应该尽量用英文表达出函数完成的功能。

遵循动宾结构的命名法则,函数名中动词在前,并在命名前加入函数的前缀,函数名的长度不得少于8个字母。

例如:

longcmGetDeviceCount(……);

3、函数参数规范:

①、参数名称的命名参照变量命名规范。

②、为了提高程序的运行效率,减少参数占用的堆栈,传递大结构的参数,一律采用指针或引用方式传递。

③、为了便于其他程序员识别某个指针参数是入口参数还是出口参数,同时便于编译器检查错误,应该在入口参数前加入const标志。

如:

……cmCopyString(constchar*c_szSource,char*szDest)

4、引出函数规范:

对于从动态库引出作为二次开发函数公开的函数,为了能与其他函数以及Windows的函数区分,采用类别前缀+基本命名规则的方法命名。

例如:

在对动态库中引出的一个图象编辑的函数定义为imgFunctionname(其中img为image缩写)。

现给出三种库的命名前缀:

①、对通用函数库,采用cm为前缀。

②、对三维函数库,采用vr为前缀。

③、对图象函数库,采用img为前缀。

对宏定义,结果代码用同样的前缀。

5、文件名(包括动态库、组件、控件、工程文件等)的命名规范:

文件名的命名要求表达出文件的内容,要求文件名的长度不得少于5个字母,严禁使用象file1,myfile之类的文件名。

三、注释规范:

1、函数头的注释

对于函数,应该从“功能”,“参数”,“返回值”、“主要思路”、“调用方法”、“日期”六个方面用如下格式注释:

//程序说明开始

//================================================================//

//功能:

从一个String中删除另一个String。

//参数:

strByDelete,strToDelete

//(入口)strByDelete:

被删除的字符串(原来的字符串)

//(出口)strToDelete:

要从上个字符串中删除的字符串。

//返回:

找到并删除返回1,否则返回0。

(对返回值有错误编码的要//求列出错误编码)。

//主要思路:

本算法主要采用循环比较的方法来从strByDelete中找到

//与strToDelete相匹配的字符串,对多匹配strByDelete

//中有多个strToDelete子串)的情况没有处理。

请参阅:

//书名......

//调用方法:

......

//日期:

起始日期,如:

2000/8/21.9:

40--2000/8/23.21:

45

//================================================================//

函数名(……)

//程序说明结束

①、对于某些函数,其部分参数为传入值,而部分参数为传出值,所以对参数要详细说明该参数是入口参数,还是出口参数,对于某些意义不明确的参数还要做详细说明(例如:

以角度作为参数时,要说明该角度参数是以弧度(PI),还是以度为单位),对既是入口又是出口的变量应该在入口和出口处同时标明。

等等。

②、函数的注释应该放置在函数的头文件中,在实现文件中的该函数的实现部分应该同时放置该注释。

③、在注释中应该详细说明函数的主要实现思路、特别要注明自己的一些想法,如果有必要则应该写明对想法产生的来由。

对一些模仿的函数应该注释上函数的出处。

④、在注释中详细注明函数的适当调用方法,对于返回值的处理方法等。

在注释中要强调调用时的危险方面,可能出错的地方。

⑤、对日期的注释要求记录从开始写函数到结束函数的测试之间的日期。

⑥、对函数注释开始到函数命名之间应该有一组用来标识的特殊字符串。

如果算法比较复杂,或算法中的变量定义与位置有关,则要求对变量的定义进行图解。

对难以理解的算法能图解尽量图解。

2、变量的注释:

对于变量的注释紧跟在变量的后面说明变量的作用。

原则上对于每个变量应该注释,但对于意义非常明显的变量,如:

i,j等循环变量可以不注释。

例如:

longlLineCount//线的根数。

 3、文件的注释:

文件应该在文件开头加入以下注释:

/////////////////////////////////////////////////////////////////////

//工程:

文件所在的项目名。

//作者:

**,修改者:

**

//描述:

说明文件的功能。

//主要函数:

…………

//版本:

说明文件的版本,完成日期。

//修改:

说明对文件的修改内容、修改原因以及修改日期。

//参考文献:

......

/////////////////////////////////////////////////////////////////////

为了头文件被重复包含要求对头文件进行定义如下:

#ifndef__FILENAME_H__

#define__FILENAME_H__

其中FILENAME为头文件的名字。

   4、其他注释:

在函数内我们不需要注释每一行语句。

但必须在各功能模块的每一主要部分之前添加块注释,注释每一组语句,在循环、流程的各分支等,尽可能多加以注释。

其中的循环、条件、选择等位置必须注释。

对于前后顺序不能颠倒的情况,建议在注释中增加序号。

例如:

......

//1、......注释

for(......)

{

}

if(......)

{//......注释

}

else

{//......注释

}

//......注释

switch(......)

{

case:

......//......注释

......

case:

......//......注释

......

default:

//......注释

......

}

在其他顺序执行的程序中,每隔3-5行语句,必须加一个注释,注明这一段语句所组成的小模块的作用。

对于自己的一些比较独特的思想要求在注释中标明。

四、程序健壮性:

1、函数的返回值规范:

对于函数的返回位置,尽量保持单一性,即一个函数尽量做到只有一个返回位置。

(单入口单出口)。

要求大家统一函数的返回值,所有的函数的返回值都将以编码的方式返回。

例如编码定义如下:

#defineCM_POINT_IS_NULLCMMAKEHR(0X200)

:

:

建议函数实现如下:

long函数名(参数,……)

{

longlResult;//保持错误号

lResult=CM_OK;

//如果参数有错误则返回错误号

if(参数==NULL)

{

lResult=CM_POINT_IS_NULL;

gotoEND;

}

……

END:

returnlResult;

}

2、关于goto的应用:

对goto语句的应用,我们要求尽量少用goto语句。

对一定要用的地方要求只能向后转移。

3、资源变量的处理(资源变量是指消耗系统资源的变量):

对资源变量一定赋初值。

分配的资源在用完后必须马上释放,并重新赋值。

例:

long*plAllocMem;//定义一个分配内存的变量。

plAllocMem=(long*)calloc(40,sizeof(long));//分配一段内存。

//处理分配内存错误

if(plAllocMem==NULL)

{

lResult=CM_MEM_ALLOC_FAILED;

gotoEND;

}

……

使用内存

……

//释放资源变量,并重新赋值。

if(pAllocMem!

=NULL)

{

free(plAllocMem);

pAllocMem=NULL;

}

4、对复杂的条件判断,为了程序的可读性,应该尽量使用括号。

例:

if(((szFileName!

=NULL)&&(lCount>=0)))||(bIsReaded==TRUE))

五、可移植性:

1、高质量的代码要求能够跨平台,所以我们的代码应该考虑到对不同的平台的支持,特别是对windows98和windowsnt的支持。

2、由于C语言的移植性比较好,所以对算法函数要求用C代码,不能用C++代码。

3、对不同的硬件与软件的函数要做不同的处理。

五、错误处理:

1、错误报告处理。

编程中要求考虑函数的各种执行情况,尽可能处理所有的流程情况。

将函数分为两类:

一类为与屏幕的显示无关,(不与用户交换信息的函数)

一类为与屏幕的显示相关。

(与用户交换信息的函数)

对于与屏幕显示无关的函数,函数通过返回值来报告错误。

对于与屏幕显示有关的函数,函数要负责向用户发出警告,并进行错误处理。

错误处理代码一般单独建立通用处理函数。

如下:

voidcmDeal_With_Error(longErrCode)

{

switch(ErrCode)

{

case1:

//注释

......

case2:

//注释

......

default:

//注释

......

}

}

2、尽早发现程序中的错误:

①、重视编译器中的警告信息。

对于编译器产生的警告信息,我们应该引起足够的重视,实际上许多警告信息指示了程序中潜在的错误危险。

所以我们要认真检查每一个警告信息,查看是否有某种隐患。

尽量消除警告信息。

②、利用断言来检查错误

对于程序中的某种假设,或防止某些参数的非法值,利用断言来帮助查错是一种好的办法。

例如下面的函数:

longcmMemCpy(void*pvToMem,void*pvFromMem,size_twSize)

{

……

if(pvToMem==NULL||pvFromMem==NULL)

{

lResult=CM_POINT_IS_NULL;

goto:

END;

}

while(wSize-->0)

{

*pvToMem++=pvFromMem++;

}

END:

returnlResult;

}

采用判断可以检查传入的指针错误,但是这样的判断是程序最终的编译代码变大,同时降低了最终发布的程序的执行效率。

由于传入空指针明显是调用这函数的程序的错误,而不是这个函数的错误,我们可以考虑采用断言来代替指针检查,即用

ASSERT(pvToMem!

=NULL&&pvFromMem!

=NULL)

代替

if(pvToMem==NULL||pvFromMem==NULL)

{

lResult=CM_POINT_IS_NULL;

goto:

END;

}

这样只会在debug版中才会产生检查代码,而在正式发布版中不会带有这些代码。

并且可以方便我们在程序调试中和测试时发现错误,同时又不影响程序的效率。

在下面的一些情况中必须加断言:

a、数的参数,特别是指针参数必须利用断言来进行确认。

b、利用断言检查程序中的各种假设的正确性。

c、在程序设计中不要轻易认为某种情况不可能发生,对你认为不可能发生的情况必须用断言来证实。

为了使程序中的断言发挥作用,所有用于在开发内部进行测试或调试的动态库、执行程序、组件必须采用debug版。

说明:

在程序效率要求较高、或者调用比较频繁的函数,对入口参数的错误检查,使用断言方式,其优点如上所叙,但其健壮性不强,所以在其他情况下,仍要求使用传统的检查方式,以增强程序的健壮性,当然,为了调试方便,可同时使用断言方式。

③、严格的测试:

对每一段代码都要求进行严格的测试,特别对一些功能函数要对其各种临界点(比如零值、无穷大的值等)进行测试。

尽量做到每一段代码零错误。

六、模块化规范:

为了提高软件的重用性,减少重复开发的工作量。

同时也为了提高程序的可读性,方便程序的维护,必须加强软件的模块化工作。

模块化应该遵循以下几个基本规范:

1、个函数应该作到精而小,函数的代码应该控制在一个适度的规模,每个函数的代码一般不能超过150行,如果超过这个规模,应该进行模块化的工作。

对于一些特殊的函数确实要超过150行,应该提交出来讨论,通过后,要求编写者更加详细的对函数注释,并写明函数超行的原因,以及设计思想等。

2、某一功能,如果重复实现三遍以上,既应该考虑模块化,将其写成通用函数。

并向开发人员发布。

并要求将接口文档和实现的功能备案。

3、每一个开发人员要尽可能的利用其他人的现成的模块,减少重复开发。

4、对函数进行模块化时,要考虑函数的层次关系,特别是在增加新的功能模块时,对原来的函数代码要进行认真的调整,做到相同功能的不同函数没有重复代码,此要求的目的在于便于代码维护。

举例如下:

现有如下函数:

//从szFileName文件中取......

long......cmGetSomething(constchar*c_szFileName,......)

{

CFile*pFile;//用来保存打开文件的地址

pFile=newCFile(c_szFileName,CFile:

:

modeRead);//用创建一个只读文件

if(pFile==NULL)

{

lResult=CM_POINT_IS_NULL;

gotoEND;

}

//从文件中读取......

......

//关闭文件

deletepFile;

END:

returnlResult;

}

若现在需要增加如下接口的新函数:

long......cmReadSomething(CFile*pFile)

{

if(pFile==NULL)

{

lResult=CM_POINT_IS_NULL;

gotoEND;

}

//从文件中读取......

......

END:

returnlResult;

}

则要求如下:

将long......cmGetSomething(constchar*c_szFileName,......)改为

long......cmGetSomething(constchar*c_szFileName,......)

{

CFile*pFile;//用来保存打开文件的地址

longlResult=CM_OK;//错误返回码

//打开文件

pFile=newCFile(c_szFileName,CFile:

:

modeRead);

if(pFile==NULL)

{

lResult=CM_POINT_IS_NULL;

gotoEND;

}

//从文件中读取......

lResult=cmReadSomething(pFile,......);

IF_ERROR_GOTO_END

//关闭文件

deletepFile;

END:

returnlResult;

}

模块化的一些注意事项:

①、设计好模块接口,用面向对象的观点看,包括:

函数接口和变量接口。

②、定义好接口以后不要轻易改动,并在模块开头(文件的开头或函数的开头)加以说明,所以在定义接口时,一定要反复琢磨,保持风格一致。

③、注意全局变量也是一种接口,如果不是确实必要,应该尽量少用全局变量。

④、在函数接口中,尽量使函数的接口容易理解和使用,其中每个输入输出参数都只代表一种类型数据,不要把错误值和其他专用值混在函数的其他输入输出参数中。

⑤、争取编写出永远成功的函数,使调用者不必进行相应的错误处理。

此规范为试行版,解释权属于**软件公司技术委员会!

员工在编写程序时请参阅FuncTemplate.h和FuncTemplate.cpp

FuncTemplate.h

//////////////////////////////////////////////////////////////////////

//工程:

FuncTemplate.h//

//描述:

用来处理对二叉树的一些算法,以及矩阵内存分配。

//

//版本:

FuncTemplate1.0版。

//

//////////////////////////////////////////////////////////////////////

typedefstruct_NODE//定义一个节点

{

struct_NODE*pLeftChild;//节点的左孩子

struct_NODE*pRightChild;//节点的右孩子

}NODE;

//==================================================================//

//功能:

用循环来实现二叉树的左序遍历//

//参数:

pNode//

//(入口)pNode:

二叉树的入口地址,即根节点的地址。

//

//(出口)无。

//

//返回:

long的函数返回码,如果返回值为CM_OK,表成功遍历,返回//

//CM_POINT_IS_NULL表二叉树指针为空。

//

//===========================================================

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 表格模板 > 书信模板

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1