C++低级错误案例整理V1x.docx

上传人:b****0 文档编号:18047981 上传时间:2023-08-07 格式:DOCX 页数:15 大小:21.02KB
下载 相关 举报
C++低级错误案例整理V1x.docx_第1页
第1页 / 共15页
C++低级错误案例整理V1x.docx_第2页
第2页 / 共15页
C++低级错误案例整理V1x.docx_第3页
第3页 / 共15页
C++低级错误案例整理V1x.docx_第4页
第4页 / 共15页
C++低级错误案例整理V1x.docx_第5页
第5页 / 共15页
C++低级错误案例整理V1x.docx_第6页
第6页 / 共15页
C++低级错误案例整理V1x.docx_第7页
第7页 / 共15页
C++低级错误案例整理V1x.docx_第8页
第8页 / 共15页
C++低级错误案例整理V1x.docx_第9页
第9页 / 共15页
C++低级错误案例整理V1x.docx_第10页
第10页 / 共15页
C++低级错误案例整理V1x.docx_第11页
第11页 / 共15页
C++低级错误案例整理V1x.docx_第12页
第12页 / 共15页
C++低级错误案例整理V1x.docx_第13页
第13页 / 共15页
C++低级错误案例整理V1x.docx_第14页
第14页 / 共15页
C++低级错误案例整理V1x.docx_第15页
第15页 / 共15页
亲,该文档总共15页,全部预览完了,如果喜欢就下载吧!
下载资源
资源描述

C++低级错误案例整理V1x.docx

《C++低级错误案例整理V1x.docx》由会员分享,可在线阅读,更多相关《C++低级错误案例整理V1x.docx(15页珍藏版)》请在冰点文库上搜索。

C++低级错误案例整理V1x.docx

C++低级错误案例整理V1x

C++低级错误案例目录

1前言

本规范用于规范C++项目组中各个局点交付版本的代码交付质量。

保证系统的质量,保证系统有效的运行。

提高编码工作效率,规避低级错误出现,指导代码评审活动开展工作。

代码案例:

2【低级错误】

2.1数组下标访问越界

(1)数组下标根据计算得出

i=a–b;

array[i]=0;//使用前应该检查i的合法性

(2)数组下标通过函数得出

voidmain()

{

inti,b[10];

getIndex(&i);

b[i]=0;//使用前应该检查i的合法性

}

(3)数组下标是循环变量

voidmain()

{

inti,max,b[10];

getMax(&max);

for(i=0;i

{

b[i]=0;

}

}

2.2变量在定义时同时未初始化

错误:

inti;//没有赋初始值

printf("i=%d\n",i);//随机分配一个值:

-858993460

自动对象的存储分配发生在定义它的函数被调用时,未初始话化的自动对象包含一个随机的位模式,是该存储区上次被使用的结果,值是不确定的。

正确:

inti=0;//定义的同时赋初始值0

2.3在循环条件中求循环次数或者大小,影响性能

错误:

for(inti=0;i<(int)attributeList.length();i++)

{

……

}

正确:

inttmp_iListLength=attributeList.length()

for(inti=0;i

{

……

}

此案例发生在广东移动业务中,数据量达5000千万用户,影响性能是秒级的,在呼叫业务中用户是不可接受的。

2.4混淆“=”与“==”

如下例子的循环判断条件中,将”==”误写成”=”,导致死循环。

错误:

Boolresult=True;

while(result=True)

{

result=execFunc();

wait();

}

正确:

while(True==result)

{

result=execFunc();

wait();

}

编程规范要求将常量写在等号左边(如“True==result”),确保编译时即可发现错误。

2.5指针使用前必须做非空检查判断

CAppService*tmp_pAppService

=dynamic_cast(m_pAppSession->getAppServiceBase());

m_pLogger=tmp_pAppService->getLogger();//tmp_pAppService指针有可能为空,那么就会core掉

正确:

CAppService*tmp_pAppService=NULL;

tmp_pAppService=dynamic_cast(m_pAppSession->getAppServiceBase());

if(tmp_pAppService!

=NULL)

{

m_pLogger=tmp_pAppService->getLogger();

}

else

{

错误处理;

}

类似数据库查询对结果集读取也应该先检查再使用

如:

ENIP:

:

IMemRecordSet*tmp_pRecordSet=t_dataSetRef.getRecordSet();

if(NULL==tmp_pRecordSet)

{

ELOG("RecordSetpointerisNULL.");

t_bHasRecord=ENIP:

:

False;

}

elseif(tmp_pRecordSet->eof())

{

LOG("NorecordfoundinLostCallServiceBlackList.");

t_bHasRecord=ENIP:

:

False;

}

在函数或方法中涉及指针或引用传递须遵循以下规则:

1.函数属于私有类型,如果内部不做检查,外部调用时必须做检查(函数内部需要加以说明);如果内部做了检查,外部调用时可以不做检查(调用时需要加以说明);

2.函数属于公有类型,函数内部必须做检查,在外部调用时可以不做检查(调用时需要加以说明);

2.6宏定义未充分封装替换参数

错误:

#defineRECT_SIZE(X*Y)

X=length+1;

Y=width+1;

最终结果为length+width+1,与预计不符合

正确:

#defineRECT_SIZE((X)*(Y))

2.7case语句遗漏break或缺少default分支条件

错误:

caseWM_CLOSE:

Close();//遗漏break语句,执行完关闭后,重新使用已释放资源

caseWM_READ:

Read();

break;

 

正确:

switch()

{

caseWM_CLOSE:

Close();

break;

caseWM_READ:

Read();

break;

default:

//不要遗漏default语句

}

2.8未判断函数返回值

错误:

//处理计费矩阵查询结果

doMatrixAnalysis(request,response)

以上代码忽略了函数的返回值检查,调用计费矩阵分析方法,函数原型如下:

intdoMatrixAnalysis(constTiChargeMatrixAnalysisReqArg&reqArg,TiChargeMatrixAnalysisResArg&resArg);

如此,有可能在后续计费执行过程出现严重错误……

正确:

if(success==doMatrixAnalysis(request,response))

{

….//计费矩阵分析成功

}

else

{

ELOG("doMatrixAnalysisfailureandreleasethecall");

t_bIsError=ENIP:

:

True;//计费矩阵分析失败,异常退出

break;

}

2.9判断无符号数是否小于0

unsignedcharc;

//c赋值为具体的循环次数,会导致死循环

while(c-->=0)

{

//dosomething…

}

 

3【1级错误】

3.1使用野指针

(1)使用未分配空间的指针

voidfunc()

{

char*p;

if(NULL!

=p)

{

printf(“%s”,p);

}

}

(2)内存空间释放后指针未置Null,内存指针仍被继续使用

void*g_pBuf=NULL;

voidATM_CellRecv(U8*pBuf,U32ulLen)

{

g_pBuf=pBuf;//g_pBuf通过pBuf赋值指向内存区域

......

if(NULL!

=pBuf)

{

free(pBuf);//只是释放了内存,而g_pBuf并没有置成NULL.

}

}

voidfunc2()

{

g_pBuf=pBuf;

if(NULL!

=g_pBuf)

{

//赋值操作,将导致非法内存改写

}

}

 

3.2内存拷贝忽略字符串结尾标志’\0’

错误:

voidfun()

{

chardest[10];

charsrc[]="0123456789";

memcpy(dest,src,sizeof(src));

}

 

正确:

voidfun()

{

charsrc[]="0123456789";

intiLenght=sizeof(src);

char*dest=newchar[iLenght];

memcpy(dest,src,iLenght);

deletepdest;

}

字符串结束符相关有许多安全函数可供调用:

snprintf,strncpy,strncat,safecopy等等,不允许使用非安全函数:

sprint,strcpy

3.3分支流程未释放动态申请的内存

voidFunction1(intnSize)

{

char*p=(char*)malloc(nSize);

if(!

GetStringFrom(p,nSize))

{

MessageBox(“Error”);

  return;

}

…//usingthestringpointedbyp;

free(p);

}

当函数GetStringFrom()返回零的时候,指针p指向的内存就不会被释放。

这是一种常见的发生内存泄漏的情形。

程序在入口处分配内存,在出口处释放内存,但是c函数可以在任何地方退出,所以一旦有某个出口处没有释放应该释放的内存,就会发生内存泄漏。

内存分配方式有三种:

  

(1)从静态存储区域分配。

内存在程序编译的时候就已经分配好,这块内存在程序的整个运行期间都存在。

例如全局变量,static变量,静态内存区。

  

(2)在栈上创建。

在执行函数时,函数内局部变量的存储单元都可以在栈上创建,函数执行结束时这些存储单元自动被释放。

栈内存分配运算内置于处理器的指令集中,效率很高,但是分配的内存容量有限。

  (3)从堆上分配,亦称动态内存分配。

程序在运行的时候用malloc申请任意多少的内存,程序员自己负责在何时用free释放内存。

动态内存的生存期由我们决定,使用非常灵活,但问题也最多。

一般我们常说的内存泄漏是指堆内存的泄漏。

堆内存是指程序从堆中分配的,大小任意的(内存块的大小可以在程序运行期决定),使用完后必须显式释放的内存。

应用程序一般使用malloc,realloc等函数从堆中分配到一块内存,使用完后,程序必须负责相应的调用free释放该内存块,否则,这块内存就不能被再次使用,我们就说这块内存泄漏了。

3.4数据类型不一致,变量或参数赋值出错

shortintx;

inty;

void*p ;

p=&x;

*(int*)p=y;

x只有两个字节的空间,而int需要4个字节的空间,实际上己出问题,编译器未设定字节对齐时会出错,在linux下不会出现入参被踩。

还有一个例子,会导致入参被踩:

intfunc(shortints,int*pi)

{

…//dosomething

*pi=0;

return0;

}

intmain(intargc,char*argv[])

{

shortintx;

shortinty;

intiRet;

…//dosomething

x=1;

iRet=func(x,(int*)&y);

}

调用函数func后,x=0。

3.5循环体内改写循环变量

unsignedlongi;

for(i=0;i<1024;c++)

{

for(i=0;i<512;c++)//尽量避免在循环中修改循环变量

{

//dosomething

}

}

3.6魔鬼数字

如:

0x01,“|”,“”,“B-DISP”;

错误:

if("B-DISP"==attributeList[i].attributeType)

{

……..

}

正确:

将字符串"B-DISP"在*.h文件中定位为字符串常量ECC_LDAPATTRS_B-DISP

constTStringECC_LDAPATTRS_B-DISP="B-DISP";

if(ECC_LDAPATTRS_B-DISP==attributeList[i].attributeType)

{

……..

}

3.7对只读参数未加const修饰

错误:

voidFunc(char*src,char*dst,intlen)

{

strncpy(src,dst,len);//误操作将src的值改写

}

正确:

voidFunc(constchar*src,char*dst,intlen)

{

strncpy(dst,src,len);

}

 

3.8各种资源句柄没有释放

FILE*fp1=fopen(“file”,w+);

....

Return0;

首次打开文件,使用后未关闭文件句柄,执行不成功。

 

正确:

FILE*fp2=fopen(“file”,a+);

......

if(NULL!

=fp2)

{

fclose(fp2);

Return0;

}

Else

{

Return-1;

}

CString中GetBuffer和ReleaseBuffer的使用;

信号量、临界区和互斥锁等同步对象资源;

线程进程资源;

3.9变量名、枚举名、常量名字面意思、注释含义与使用时相反

CVACSubScirbeReq中字段:

CMsgFieldIntm_isNeedNotifySP;//CRM侧订购的是否需要通知SP

该字段本意是个枚举值(ENUM),取值有2个:

enumisNotifySP

{

Notify_SP_NO=1,//不通知

Notify_SP_YES=2//通知SP

};

//下面的逻辑是需要通知sp才处理的,枚举含义和实际意义完全颠倒

if(From_CRM==pSessionInfo->m_reqInfo.m_CRMOrderFlag.asInt()

&&Notify_SP_NO==pSessionInfo->m_reqInfo.m_isNeedNotifySP.asInt())

3.10所有的可能抛异常的地方都要有捕获

constchar*sql="selectmsisdn,serviceid,spid,billmonth,amount,account,rewardAmount,rewardAccount,realaccountfromhistoryrecordwheremsisdn=:

v1andserviceid=:

v2andspid=:

v3";

TINTnCommandIndex=m_pDbAgent->excute(sql,msisdn,pa,paCount);

if(nCommandIndex==Failed)

{

returnSearchResult_DBError;

}

CRecordSetrs;

rs.setSACommand(&CDBAgent:

:

getInstance()->s_commandSet[nCommandIndex]);

//完全没有try和catch保护,一旦数据库出错就是一个core

4【2级错误】

4.1循环变量数据类型太小

unsignedcharc;

unsignedshorts;

//dosomething

//s>255

for(c=0;c

{

//dosomething

}

4.2函数局部变量或参数过大,堆栈溢出

voidFunction(void){

charb[0x200000];

}

intmain()

{

ret=function();

}

函数参数的输入、输出如果是一个比较大的结构,要用指针带入保存输入数据的内存地址,用指针带入保存输出的内存地址,不要直接用值传递的方式输入和输出。

如果函数的较大的输入输出使用值传递方式,对函数堆栈处理有较大的开销。

当数据接近或者大于堆栈空间的时候,就会出现堆栈溢出错误

如果是使用DOPRA平台,可以在v_configkernel.h文件中找到默认的栈大小

#defineVOS_DEFAULT_STACK_SIZE0x200000

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

当前位置:首页 > IT计算机 > 计算机硬件及网络

copyright@ 2008-2023 冰点文库 网站版权所有

经营许可证编号:鄂ICP备19020893号-2