软件代码评审检查点--C-C++

整理文档很辛苦,赏杯茶钱您下走!

免费阅读已结束,点击下载阅读编辑剩下 ...

阅读已结束,您可以下载文档离线阅读编辑

资源描述

软件代码评审检查点--C-C++文件结构审查【检查点1】文件名是否和实际内容相符?[规范性]〖说明〗文件名应该清晰说明出该文件的功能和作用。〖案例〗略【检查点2】多个模块公用的定义和函数原型的说明是否放在“*.h”?〖说明〗一般来说,*.h文件是公用的头文件,文件中申明的宏、结构、函数原型等,一其他的模块需要引用。〖案例〗略【检查点3】私有的申明和函数原型的说明是否放在“*.inc”?〖说明〗一般来说,*.inc文件是私有的头文件。文件中申明的宏、结构、函数原型等,是仅供本模块使用。〖案例〗略【检查点4】头文件是否使用了#ifndef---#endif宏开关来防止重复引用?〖说明〗一般来说,头文件通过如下方法避免重复引用:#ifndef_XXX_H_#define_XXX_H_/*文件主体*/#endif【检查点5】函数原型是否没有明确申明返回值类型〖说明〗虽然C语言并不需要精确定义和声明函数返回类型,如果函数没有返回值,则定义为类型void。如果函数没有定义返回类型,编译器将认为其返回类型为int。在这种情况,很难判断函数是否应该有返回值。为了避免这种情况,函数返回类型应该被定义和声明。〖案例〗错误书写:SSfunction();正确书写:voidSSfunction();预处理【检查点1】宏定义是否缺少了“()”符号?〖说明〗对于表达式的宏定义,注意要对变量和表达式本身使用“()”,防止宏展开时出错。〖案例〗案例一注意下面的宏定义极易出现问题:#defineADD(x,y)x+y上面的宏在如下代码中出错:c=ADD(a,b)/2;宏展开后的形式为:c=a+b/2;而不是:c=(a+b)/2;案例二#defineMULTI(x,y)x*y在程序中代码如下:a=MULTI(b+c,2);宏展开后为:a=b+c*2;而不是:a=(b+c)*2;【检查点2】宏定义是否存在不期望或者意料之外的附加效应?〖说明〗宏是一个短行的文本,或者说文本模板,它可以被扩充为更长的文本.通常由宏产生的问题并不在宏定义本身,而往往由其下面的程序引起.采用宏可以使代码简化,但它也可能隐藏重要的细节和关键的操作.〖案例〗#defineSQUARE(x)((x)*(x))...w=SQUARE(++value);实际对宏SQUARE的引用将导致value被增加两次,因为这个语句将被C预处理器扩充以下形式:w=((++value)*(++value));【检查点3】是否存在通过定义宏来改变程序控制流程?〖说明〗通过定义宏来改变程序控制流程实际上是很糟糕的编程技巧〖案例〗错误形式:#defineFOR_ALLfor(i=0;isize;i++).../*CleartheCarray*/FOR_ALL{c[i]=0;}【检查点4】在函数定义中使用条件预处理,所定义的标志所致使的代码差别是否很大?〖说明〗在函数定义中使用条件预处理只能用于程序中基于所定义的标志所致使的代码的轻微差别.大的差别应该由不同的函数来处理.〖案例〗【检查点5】函数内部的条件预处理是否遍及整个函数?〖说明〗在函数定义中使用条件预处理只能用于程序中基于所定义的标志所致使的代码的轻微差别.大的差别应该由不同的函数来处理.〖案例〗【检查点6】一个条件预处理是否使一个完整的C语句分为几段?〖说明〗不应该让一个条件预处理使一个完整的C语句分为几段.〖案例〗错误形式:if((cond==GLRUN)#ifdefFEAT_A||(cond==GLWAIT)#endif){正确形式:#ifdefFEAT_Aif(cond==GLRUN||cond==GLWAIT)#elseif(cond==GLRUN)#endif{【检查点7】include中是否包含了绝对路径?〖说明〗#include包含的文件路径应该是相对路径,不应该使用绝对路径,经常出现错误主要是带有盘符,带有根目录符号的写法。〖案例〗以下使用方法在程序中应该禁止:#includec:\include\type.h/*不应该包括“c:\”*/#include\test\include\macro.h/*不应该包括“\”根目录符号*/正确的写法为:#includetest\include\type.h#includetest\include\macro.h函数【检查点1】是否对函数的输入参数进行应有合法性检查?〖说明〗对于给其他模块使用的公用函数,要求函数内部对输入参数进行严格全面的参数检查。对于模块内的私有函数,在不是很影响效率的情况下,建议进行全面的参数检查。【检查点2】是否函数完成了必要的功能性?〖说明〗略【检查点3】传送一个数据结构或者一组变量而这些变量需要被修改的情况下,是否传送一个指针更为有效?〖说明〗〖案例〗错误形式:return(MLtisfail(mltmsg-cmd.req.req2,tmrc));正确形式:return(&MLtisfail(mltmsg-cmd.req.req2,tmrc));在如下这些情况下传送指针作为参数是更好的选择:---需要传送大量的数据和大型的数据结构作为输入时,---被调函数需要修改调用函数的数据时.【检查点4】返回值的所携带的信息是否的确是调用函数所需要的?〖说明〗略【检查点5】函数入参是间接引用参数时候,当中是否漏掉一个层次?〖说明〗〖案例〗错误形式:DXal_fndnxt(...,(DXALMDATA*)&data_ptr);正确形式:DXal_fndnxt(...,(DXALMDATA**)&data_ptr);【检查点6】函数退出时是否有正确的返回值?〖说明〗看到函数调用,要养成习惯,进入函数内部瞄一眼。看看函数的正常值和异常值都是什么。看看返回值需不需要判断。看看有没有参数理解不一致的地方。〖案例〗错误形式:if(VOS_strnicmp(szFullName,DEV_ATM_NAME,DEV_ATM_NAMELEN)==0){ulIfType=DEV_GetIfTypeFromIfName(szFullName);if(ulIfType==-1){EXEC_OutString(ulExecID,\r\nUnknowninterfacetype);returnVOS_ERR;}/*得到端口的索引*/ulRet=DEV_GetIfIndexFromIfName(szFullName,&ulIfIndex);if(SUCCESS!=ulRet){EXEC_OutString(ulExecID,\r\nUnknowninterfacenumber);returnVOS_ERR;}/*判断端口是否已经存在*/pIfIns=DEV_GetIfFromIndex(ulIfIndex);if(NULL==pIfIns){rc=DEV_Cnsl_CreateIf(ulExecID,ulIfType,ulIfIndex,ulSubType);if(SUCCESS!=rc){returnSUCCESS;}pIfIns=DEV_GetIfFromIndex(ulIfIndex);if(NULL==pIfIns){COUT_OUTPUT_DIAG(MOD_DEV,COUT_LEVEL_WARNING,pIfIns=NULLisinvalid%s.%d,__FILE__,__LINE__);returnDEV_ERR_GEN;}}}函数使用-1作为非法值,而在DEV_GetIfTypeFromIfName函数中:U32DEV_GetIfTypeFromIfName(CHAR*ifName){CHARszIfType[20];//接口的类型字符串U32ulIfType;U32strLen;U32i;if(NULL==ifName){COUT_OUTPUT_DIAG(MOD_DEV,COUT_LEVEL_WARNING,ifName=NULLinGetIfTypeFromIfName%s.%d,__FILE__,__LINE__);returnDEV_ERR_VALUE;}strLen=VOS_strlen(ifName);if(0==strLen){/*字符串为空,返回错误*/COUT_OUTPUT_DIAG(MOD_DEV,COUT_LEVEL_WARNING,strlen=0%s.%d,__FILE__,__LINE__);returnDEV_ERR_VALUE;}}VOS_Mem_Set(szIfType,0,sizeof(szIfType));/*---------------------------------------------------------*//*从字符串的尾部向前查找,直到找到第一个不是数字的字符*//*---------------------------------------------------------*/for(i=strLen-1;i=0;i--){/*字符不等于'.','/'或数字字符时循环结束*/if(ifName[i]!='.'&&ifName[i]!='/'&&(ifName[i]'0'||ifName[i]'9'))break;}VOS_strncpy(szIfType,ifName,i+1);ulIfType=DEV_IfStringToType(szIfType);returnulIfType;}函数的一个错误返回值是DEV_ERR_VALUE,很显然,两边参数理解不一致。【检查点7】调用其他函数时是否对返回值进行了判断?〖说明〗略【检查点8】在函数调用前是否认真核实传参的数据类型?〖说明〗〖案例〗错误形式:(void)CCbinasc(loop_ptr-annc_rtidx,...);正确形式:(void)CCbinasc((DMUNLONG)loop_ptr-annc_rtidx,...);【检查点9】在多任务操作系统环境下是否考虑了函数的可重入性?〖说明〗在多任务的操作系统中,对于多任务共用的函数,如果该函数用到了全局变量或静态变量,需要注意到函数的可重入性。一般来说,如果函数只使用了内部的非静态局部变量,则该函数没用可重入的问题【检查点10】当一个指针被传给一个函数,并且被调用的函数试图增加或减少这个指针所指示的内容时是否出现了常见错误?〖说明〗此时容易出现常见错误〖案例〗案例一这个例子中,尽管++和*操作符拥有相同操作优先级.但它们是按从右到左的顺序执行的.错误形式:*numretry++;正确形式:(*numretry)++;案例二另一个常见的错误发生在当你试图调用一个函数并取其返回值,然后在一个条件判断表达式中测试这个返回值时.错误形式:if((rtc=_ims_open(NPRD_CH)!=_SUCCESS)){正确形式:if((rtc=_ims_open(NPRD_CH))!=_SUCCESS){【检查点11】函数定义中增添了一个参数时,是否有在所有该函数调用的场合完成对应修改?〖说明〗(函数被调用而参数未被充分传递的错误也因之而生).如果新的参数是加到原来所定义的参数序列的开始或中间位置时问题将更加严重.发生这种问题时,所有从这一点起前面已经存在的参数都被错位了.下面这个例子说明这个问题.〖案例〗函数调用传送了三个参数:DBnswch_mem(&omsg,&smtimr,grwsize);但是函数定义了四个参数:DBnswch_mem(OSPID,*omsg,*timr,grwsize);【检查点13】一组错误类型是否也归入这个子标题所表示的错误类型?〖说明〗调用printf及其相关的这组类型函数时传递了不恰当数量的参数数量.问题来自于可能传递了更多或更少于转义字符的变量参数给打印函数.〖案例〗错误形式:sprintf(infile,/rclog/tmp.evl%d.5E3l);错误形式:sprintf(corclog,/log/cpcorc,0);【检查点14】fprintf()和printf()是否

1 / 22
下载文档,编辑使用

©2015-2020 m.777doc.com 三七文档.

备案号:鲁ICP备2024069028号-1 客服联系 QQ:2149211541

×
保存成功