编程规范讲义课件

PPT
  • 阅读 56 次
  • 下载 0 次
  • 页数 80 页
  • 大小 588.501 KB
  • 2022-11-24 上传
  • 收藏
  • 违规举报
  • © 版权认领
下载文档30.00 元 加入VIP免费下载
此文档由【小橙橙】提供上传,收益归文档提供者,本网站只提供存储服务。若此文档侵犯了您的版权,欢迎进行违规举报版权认领
编程规范讲义课件
可在后台配置第一页与第二页中间广告代码
编程规范讲义课件
可在后台配置第二页与第三页中间广告代码
编程规范讲义课件
可在后台配置第三页与第四页中间广告代码
编程规范讲义课件
编程规范讲义课件
还剩10页未读,继续阅读
【这是免费文档,您可以免费阅读】
/ 80
  • 收藏
  • 违规举报
  • © 版权认领
下载文档30.00 元 加入VIP免费下载
文本内容

【文档说明】编程规范讲义课件.ppt,共(80)页,588.501 KB,由小橙橙上传

转载请保留链接:https://www.ichengzhen.cn/view-45443.html

以下为本文档部分文字说明:

单击此处键入子标题软件编程规范引言据说程序员的黄金年代已经过去,听着好象有点感伤的味道。那时候,程序员个个留着长发,不修边幅,光着脚丫子,喜欢抱着键盘坐在地上,写一些别人看不懂他也没想着要别人看懂的东西。今天人们越来越明白软件设计更多地是一种工程,而不是一种艺术,居然有人很恶毒地发明了一种

叫软件工程的东西来加速程序员黄金年代的结束。而我们的代码和我们的人本身也不得不渐渐变得西装革履起来。什么是软件编程规范?为了提高源程序的质量和可维护性,最终提高软件产品生产力,对软件产品的源程序的编写风格作出统一的规范约束。风格,约定红宝书:SteveMa

guire,《编程精粹》为什么要有编程规范?目的:提高源程序的质量和可靠性可读可维护举例:印度软件人员笔试,代码一模一样。GNU编码标准分类1)语言:C/C++,Java,Delphi等2)范围:主机,单板软件1)我司编程规范怎么形成的

?我司的经验印度和美国公司的文档2)谁维护它?软件工程室如何使用编程规范?1)开发人员在写代码时按照规范编写2)项目组对开发人员编写的代码进行检查人员:设计、开发、测试、质量形式:结合到其它的检查工作中完成,如代码的正规检视,代码走读对象:所有未归档的重点

代码时间:在编码完成、尚未开始调试和单元测试时公司文件数据库:研发体系文件夹(rnd-apps/huawei)文件名:research_files.nsf华为研发办字[1999]18号软件编程规范总则华为研发办字[1999]64号软件编程规范主机、

终端、数据库分则华为研发办字[1999]73号单板软件编程规范内容两部分内容:一、规则二、常见错误第一部分规则以下分两部分给出了一些基本准则,一个是关于程序书写风格的,一个是关于程序质量保证的。每条准则都有例外。如果某人对你说:"不能闯红灯",虽这是一条准则,但你肯定能

够举出一种特殊情况,在这种情况下闯红灯倒是个正确的行动。这里关键是要记住准则只是在一般情况下才有意义,因此只有理由十分充足时,才可以违背准则。规则目录1排版2注释3命名4可读性5变量6函数7可测性8效率9质量保证1排

版1)程序块要采用缩进风格编写,缩进的空格数为4个。2)相对独立的程序块之间、变量说明之后必须加空行。3)长句要分成多行书写说明:长表达式要在低优先级操作符处划分新行,操作符放在新行之首。例14)对齐只使用空格键,不使用TAB键。4)双目操作符之前、之后或者前后

要加空格。5)一行程序以小于80字符为宜。示例1:长语句perm_count_msg.head.len=NO7_TO_STAT_PERM_COUNT_LEN+STAT_SIZE_PER_FRAM*sizeof(_UL);report_or_not_flag=((taskno<

MAX_ACT_TASK_NUMBER)&&(n7stat_stat_item_valid(stat_item))&&(act_task_table[taskno].result_data!=0));示例2:函数theDatabase

.Search(pUserQuery->Criterium,CurrentSession.pDomain,&SearchCursor);2注释注释按功能级别可分三类:1.模块(文件)注释;在模块或文件头部进行描述,它对整个模块或文件所要完成的功能进行描述,它的侧重点在于模块关系和功能描述,修改记录

一般也放在这里。2.函数(过程)注释;在函数(或过程)前进行描述,例子中给出的就是函数(过程)注释,它主要提供函数(过程)的接口说明,其内容包括基本功能描述、出入口参数、调用关系,如有必要,将实现算法

也包括在内。3.代码块注释;在函数(或过程)体中描述,它对某个代码块的功能进行说明,包括对临时变量进行说明。1)有效注释量必须在20%以上。2)注释应与其描述的代码相近:上方或右方。3)函数头部应进行注释,列出:函数的目的/功能、输入参数、输出参数、返回值、调用关系(函数、表)等。4)对数据结构

的注释应放在其上方相邻位置;对结构中的每个域的注释放在此域的右方。5)全局变量注释包括对其功能、取值范围、哪些函数或过程存取它以及存取时注意事项等的说明。6)对变量的定义和分支语句(条件分支、循环语句等)必须编写注释。7)使用中文注释。例:说明性文件注释/******

*******************************************Copyright﹫,1988-1999,HuaweiTech.Co.,Ltd.Filename://文件名Author:Version:Dat

e://作者、版本及完成日期Description://用于详细说明此程序文件完成的主要功能,与其他模块//或函数的接口,输出值、取值范围、含义及参数间的控//制、顺序、独立或依赖等关系Others://其它内容的说明FunctionList://主要函数列表,

每条记录应包括函数名及功能简要说明1.....History://修改历史记录列表,每条修改记录应包括修改日期、修改//者及修改内容简述1.Date:Author:Modification:2....******************************

*******************/例:函数注释/*************************************************Function://函数名称Description://函数功能、性能等的描

述Calls://被本函数调用的函数清单CalledBy://调用本函数的函数清单TableAccessed://被访问的表(仅对于牵扯到数据库操作的程序TableUpdated://被修改的表(仅对于牵扯到数据库操作的程序Input://输入

参数说明,包括每个参数的作//用、取值说明及参数间关系。Output://对输出参数的说明。Return://函数返回值的说明Others://其它说明*************************************************/例:结构注释/*sccpi

nterfacewithsccpuserprimitivemessagename*/enumSCCP_USER_PRIMITIVE{N_UNITDATA_IND,/*sccpnotifysccpuserunitdatacom

e*/N_NOTICE_IND,/*sccpnotifyusertheNo.7networkcannot*//*transmissionthismessage*/N_UNITDATA_REQ,/*sccpuser'sunitdat

atransmissionrequest*/};3标识符命名1)变量命名禁止取单个字符如i、j、k。说明:局部变量如果用单个字符表示,很容易敲错。但i、j、k作局部循环变量是允许的。2)命名与所使用的系统风格保持一致。说明:如采用UNIX的全小写加下划线的风格或

大小写混排的方式,不要使用大小写与下划线混排的方式;用作特殊标识如标识成员变量或全局变量的m_和g_,其后加上大小写混排的方式是允许的。2)匈牙利命名法说到命名约定,就不得不提一下Microsoft的天才

程序员CharlesSimonyi。他在Xerox的PaloAlto实验室工作时开发了"匈牙利式"命名约定,该命名法通过在数据和函数名中加入额外的信息以增进程序员对程序的理解。例如:charch;/*所有

的字符变量均以ch开始*/byteb;/*同理*/longl;/*所有的长字均冠以l*/在Microsoft公司中,匈牙利命名法在应用程序部门得到了良好的应用,但在系统部门却并没有得到这样的待遇。实际上,使用此命名法有一个很实际的问题,不容易扩展到处理typedef和C++类。4)命名中的缩

写三种方法:1.抽取元音字母task-->tskuser-->usr2.取单词意义明显的头部maximum-->maxminimum-->min3.惯例,实际上是先用(2)后用(1)进行处理而得temporary-->tmpremove-->

rm限制:如果缩写导致该名字的意义不明确,就不要使用它。示例1:Add_User×add_user、AddUser、m_AddUser√示例2:#define_EXAMPLE_0_TEST_×#define_EXAMPLE_1_TEST_×voidset_sls00(BYTEsl

s);×例:匈牙利命名intliv_Width其变量名解释如下:l局部变量(Local)(其它:g全局变量(Global)...)i数据类型(Interger)v变量(Variable)(其它:c常量(Const)..

.)Width变量含义这样可以防止局部变量与全局变量重名。4可读性1)用括号明确表达式的操作顺序,不使用默认优先级。2)不使用不易理解的数字,用有意义的标识来替代。说明:涉及物理状态或者含有物理意义的常量,

不应直接使用数字,必须用有意义的枚举或宏来代替。3)不要使用难懂的技巧性很高的语句。说明:高技巧语句不等于高效率的程序,实际上程序的效率关键在于算法。示例:*stat_poi+++=1;×*++stat_poi+=1;×5变量、结构1)明确公共变量与操作此公共变量的

函数或过程的关系,如访问、修改及创建等。说明:明确过程操作变量的关系后,将有利于程序的进一步优化、单元测试、系统联调以及代码维护等。2)防止局部变量与公共变量同名。说明:若使用了较好的命名规则,那么此问题可自动消除。3)严禁使用未经初始化的变量作为右值。说明:特别是在C/C++中引

用未经赋值的指针,经常会引起系统崩溃。4)公共变量只有一个模块或函数可以修改、创建。说明:降低公共变量耦合度。5)使用严格形式定义的数据类型,不使用与具体硬件或软件环境关系密切的变量。说明:使用标准的数据类型,有利于程序的移植。6)结构:

一个功能,一种事务的抽象。说明:设计结构时应力争使结构代表一种现实事务的抽象,而不是同时代表多种。结构中的各元素应代表同一事务的不同侧面,而不应把描述没有关系或关系很弱的不同事务的元素放到同一结构中。7)结构间的关系不要过于复杂。

说明:若两个结构间关系较复杂、密切,那么应合为一个结构。8)若结构中元素个数过多把元素组成不同的子结构。说明:增加结构的可理解性、可操作性和可维护性。9)不使用数据类型默认转换与强制转换。说明:当进行数据类型强制转换时,其数据的意义

、转换后的取值等都有可能发生变化,可能留下隐患。10)使用自定义类型。11)分布式环境或不同CPU间通信环境的数据结构的字节顺序。说明:IntelCPU与Motorola68360CPU,在处理位域及整数时,其在内存存放的“顺序”正好相反。12)

在对齐方式下,CPU的运行效率要快得多。示例1:公共变量变量/函数System_InitInput_RecStat_ScoreStudent创建修改访问Score创建修改访问,修改其中,函数Input_Rec、Stat_Score都可修改变量Sco

re,故此变量将引起函数间较大的耦合,并可能增加代码测试、维护的难度。示例2:在DOS下BC3.1环境中代码,在移植时可能产生问题。voidmain(){registerintindex;//寄存器变量_AX=0x4000

;//_AX是BC3.1提供的寄存器“伪变量”...//programcode}示例3:结构typedefstructSTUDENT_STRU{unsignedcharname[8];/*student抯name*/unsignedcharage;

/*student抯age*/unsignedcharsex;/*student抯sex,asfollows*//*0-FEMALE;1-MALE*/unsignedcharteacher_name[8];/*thestudentteacher抯name*/unisgnedcharteacher

_sex;/*histeachersex*/}STUDENT;示例4:自定义类型typedefunsignedcharBYTE;typedefunsignedshortWORD;typedefunsignedintDWORD;示例5:对齐如下图,当一个long型数(如图中l

ong1)在内存中的位置正好与内存的字边界对齐时,CPU存取这个数只需访问一次内存,而当一个long型数(如图中的long2)在内存中的位置跨越了字边界时,CPU存取这个数就需要多次访问内存,如i960cx访问这样的数需读内存三次(

一个BYTE、一个SHORT、一个BYTE,由CPU的微代码执行,对软件透明),所有对齐方式下CPU的运行效率明显快多了。18162432----------------------------|long1|long1|long1|long1|-

---------------------------||||long2|-----------------------------|long2|long2|long2||-----------------------------6函数1)可重入函数的局

部变量的使用。说明:编写C/C++可重入函数时,使用auto即缺省态局部变量或寄存器变量,不使用static局部变量,否则必须经过特殊处理,才能使函数具有可重入性。2)编写可重入函数时使用全局变量,通过关中断、信号量(即P、V操作)等手段加以保护。说明:若对所使用的全局变量不加以保护,则此函数就

不具有可重入性,即当多个进程调用此函数时,很有可能使有关全局变量变为不可知状态。3)对接口函数参数进行合法性检查。说明:这一问题往往有两个极端:要么是调用者和被调用者对参数均不作合法性检查,造成问题隐患;要么就是调用者和被调用者均对参数

进行合法性检查,产生了冗余代码。4)禁止将函数的参数作为工作变量。说明:将函数的参数作为工作变量,有可能错误地改变参数内容,很危险。方法:先用局部变量代之,最后再将该局部变量的内容赋给该参数。5)函数的规模尽量限制

在200行以内。说明:不包括注释和空格行。6)一个函数仅完成一件功能。7)非调度函数禁止使用控制参数,只使用数据参数。说明:调度函数是指根据输入的消息类型来启动相应的功能实体,而本身并不完成具体功能。控制参数是指改变函数功能行为的参数,即函数要根据此参数来决定具体怎样工作。非调度函数

的控制参数增加了函数间的控制耦合,使函数间的耦合度增大,并使函数的功能不唯一。8)检查函数输入的有效性。说明:函数的输入主要有两种:一种是参数输入;另一种是全局变量、数据文件的输入,即非参数输入。9)不把与函数返回值类型不同的变量进行强制的转换后作为返回值返回。

在调用函数填写参数时,不进行默认数据类型转换或强制数据类型转换。10)设计高扇入、合理扇出(小于7)的函数。说明:扇出是指一个函数直接调用(控制)其它函数的数目,而扇入是指有多少上级函数调用它。函数较合理的扇出通常是3-5(调度函数除外)

。11)不进行函数本身或函数间的递归调用。影响:理解性;系统资源(如栈空间);测试。12)优化函数结构。说明:对初步划分后的函数结构应进行优化。优化原则:(1)不能影响模块功能的实现。(2)考查出错处理和模块的性能要求进行完善。(3)通过分解或合并函数来改进软件结构。(4)规模大的

函数要进行分解。(5)降低函数间接口的复杂度。(6)不同层次的函数调用要有较合理的扇入、扇出。(7)函数功能应可预测。(8)提高函数内聚。(单一功能的函数内聚最高)13)禁止使用BOOL参数。说明:1、无意义;2、不利于扩充。例:重入xam是int型全局变量,函数Squre_Exam返回Ex

am平方值。那么如下函数具有可重入性。signedintexample(intpara)unsignedinttemp;Exam=para;//(**)temp=Square_Exam();returnte

mp;函数若被多个进程调用结果可能是未知的;当(**)语句刚执行完后,另一个用本函数的进程可能正好被激活,当新激活的进程执行到此函数时,将使Exam与另一个不同的para值,所以当控制重新回到“temp=Square_Exam()”后,算出的temp很可能不是预想中的结果。7可测性1

)统一的调测开关和打印函数。说明:调测打印格式要有统一的形式。信息串中至少要有所在模块名(或源文件名)及行号。调测开关应分为不同级别和类型。2)测试代码部分作为一个子模块。3)使用断言来发现问题,提高可测性。说明:断言是对某种假设条件进行检查,可理解为若条件成立则

无动作,否则报告。它可以快速发现并定位软件问题,同时自动报警。SteveMaguire,《编程精粹》4)断言:调测时可能发生的非法情况,正常运行时不应发生。断言处理最终产品肯定会出现且必须处理的错误情况×说明:断言是用来处

理不应该发生的错误情况的,对于可能会发生的且必须处理的情况要写防错程序,而不是断言。如某模块收到其它模块或链路上的消息后,要对消息的检查是正常的错误检查,不能用断言来实现。5)编写防错程序,在处理错误后用

断言宣布发生错误。6)用调测开关来切换软件的DEBUG版和正式版。示例:C语言断言(其中NULL为0L)#ifdef_EXAM_ASSERT_TEST_//若使用断言测试voidexam_assert(char*file_name,unsignedintline_n

o){printf("\nAssertfailed:%s,line%u\n",file_name,line_no);//abort();}#defineASSERT(condition)if(condition)//若条件成立,则无动作NULL

;else//否则报告exam_assert(__FILE__,__LINE__)#else//若不使用断言测试#defineEXAM_ASSERT(condition)NULL#endif/*endofASSERT*/8程序效率1)在保证软件系统的正确性、稳定性、可读性及可测性的前提下,提高代码

效率。2)系统数据结构程序算法空间效率例143)循环体内工作量最小化。例154)在多重循环中,应将最忙的循环放在最内层。例16说明:减少CPU切入循环层的次数。5)避免循环体内含判断语句,如果判断语句与循环变量无关,应将循环语句置于判断语句的代码块之中。说明:目的是减少判断

次数。6)尽量用乘法或其它方法代替除法。例1:空间效率如下记录学生学习成绩的结构不合理。typedefunsignedcharBYTE;typedefunsignedshortWORD;typedefstruct

STUDENT_SCORE_STRU{BYTEname[8];BYTEage;BYTEsex;BYTEclass;BYTEsubject;floatscore;}STUDENT_SCORE;分为两个结构,总的存贮空间变小,操作也

变得更方便。typedefstructSTUDENT_STRU{BYTEname[8];BYTEage;BYTEsex;BYTEclass;}STUDENT;typedefstructSTUDENT_SCORE_STRU{WORDstudent_index;BYTE

subject;floatscore;}STUDENT_SCORE;例:如下代码效率不高。for(ind=0;ind<MAX_ADD_NUMBER;ind++){sum+=ind;back_sum=sum;/*backupsum

*/}语句“back_sum=sum;”完全可以放在for语句之后。例:如下代码效率不高。for(row=0;row<100;row++){for(col=0;col<5;col++){sum+=a[row][col];}}可以改为如下方式,以提高效率。for(col=0;col<5;col++)

{for(row=0;row<100;row++){sum+=a[row][col];}}9质量保证1在软件设计过程中构筑软件质量。2代码质量保证优先原则。(1)正确性,指程序要实现设计要求的功能。(2)稳定性、安全性,指程序稳定、可靠、安全。(3)可测试

性,指程序要具有良好的可测试性。(4)规范/可读性,指程序书写风格、命名规则等要符合规范。(5)全局效率,指软件系统的整体效率。(6)局部效率,指某个模块/子模块/函数的本身效率。(7)个人表达方式/个人方便性,指个人编程

习惯。3只引用属于自己的存贮空间。4防止引用已经释放的内存空间。5过程/函数中分配的内存,在过程/函数退出之前要释放。6过程/函数中申请的(为打开文件而使用的)文件句柄,在过程/函数退出之前要关闭。7防止内存操作越界。说明:内存操作主要

是指对数组、指针、内存地址等的操作。8系统运行之初,要初始化有关变量及运行环境,防止未经初始化的变量被引用。9要防止差1错误。说明:此类错误一般是由于把“<=”误写成“<”或“>=”误写成“>”等造成的,由此引起的后果,很多情况下是

很严重的,所以当编完程序后,应对这些操作符进行彻底检查。10注意易混淆的操作符说明:如C/C++中的“=”与“==”、“|”与“||”、“&”与“&&”等,若拼写错了,编译器不一定能够检查出来。11if语句尽量加上else分支,对没有else分支的语句要小心

对待;switch语句必须有default分支。12不使用goto语句。13时刻注意表达式是否会上溢、下溢。14使用变量时要注意其边界值的情况。例17例:变量边界如C语言中字符型变量,有效值范围为-128到1

27。故以下表达式的计算存在一定风险。charchr=127;intsum=200;chr+=1;//127为chr的边界值,再加1将使chr上溢到-128,而不是128。sum+=chr;//故sum的结果不是328,而是7

2。若chr与sum为同一种类型,或按如下方式书写,就没有问题sum=sum+chr+1;10编辑、编译1要小心地使用编辑器提供的块拷贝功能编程。2打开编译器的所有告警开关对程序进行编译。3使用代码检查工具

(如C语言用PC-Lint)对源程序检查。4使用软件工具(如LogiSCOPE)进行代码审查。11宏1用宏定义表达式时,要使用完备的括号。例182将宏所定义的多条表达式放在大括号中。例193使用宏时,不允许参数发生变化。例20例:

使用括号#defineRECTANGLE_AREA(a,b)a*b#defineRECTANGLE_AREA(a,b)(a*b)#defineRECTANGLE_AREA(a,b)(a)*(b)正确的定义应为:#defineRECTANGLE_AREA(a,b)((a)*(b

))例:使用大括号下面的语句只有宏的第一条表达式被执行。#defineINTI_RECT_VALUE(a,b)\a=0;\b=0;INTI_RECT_VALUE(rect.a,rect.b);正确的用法应为:#defineINTI_RECT_VALUE(a,b)\{\

a=0;\b=0;\}INTI_RECT_VALUE(rect.a,rect.b);例:参数变化示例:如下用法可能导致错误。#defineSQUARE(a)((a)*(a))inta=5;intb;b=SQUARE(a++);//结果:a=7,即执行了

两次增1。正确的用法是:b=SQUARE(a);a++;//结果:a=6,即只执行了一次增1。第二部分常见错误通过对常见错误的整理,使大家不再犯类似的错误1指针操作使用指针虽然灵活,但也对程序的稳定性造成一定威胁,主要原因是当要操作一个指针时,此指针可能正指向一个非法的地址。因此每个

开发人员都必须格外小心,以防引起错误,并且在使用指针前最好对其合法性进行检查(比如用断言或直接检查指针是否合法等手段)。安安全全地使用一个指针并不是一件容易的事,所以在没有必要使用指针的地方,就别用。_UC*puc_card_config_tab;.

.....Get_Config_Table(AMP_CPM_CARD_CONFIG_TABLE,&ul_card_config_num,&puc_card_config_tab,use_which_data_area);......b_middle_d

ata_ok=generate_trans_middle_data_from_original_data(puc_card_config_tab,Ul_card_config_num)其中红色部分巧妙的利用指向指针的指针为指针puc_card_config_tab赋值,而在兰色部分使

用该指针。但在Get_Config_Table函数中有可能失败返回而不给该指针赋值。因此,以后使用的可能是一个非法指针。2公共变量的操作公共变量是引起程序不稳定的另一个主要因素,因此公共变量除了要有详细的注释说明外,引用时还

应特别注意。比如某公共变量Current_Task_No,合法值为0-100,那么当你每次修改它时都要确认修改后的值为正确范围;当引用时,应首先判断其合法性(根据实际情况,可用断言或直接判断)。故编程时应尽量少用公共变量,而没有必要的公共变量更是多余的

。3局部变量的使用关于局部变量,应注意以下问题:由于非static局部变量(在程序运行到此函数时)占用的是堆栈空间,故不应声明得过大,否则容易造成堆栈溢出。较大的局部变量最好声明成static变量。假如某函数的返回值为指针型,那么

不可把非static的局部变量的地址作为返回值返回。非static局部变量的值,在函数返回后将会消失,而static局部变量则不会,编程时要注意它们的区别。4不经意的赋值语句如:if(Connection_Stat

e[index].state==STATE_IDLE)写成:if(Connection_State[index].state=STATE_IDLE)建议在比较判断语句中,把常量放在前面,这样编译器就可查出这种错误。如:if(STATE_IDLE==Con

nection_State[index].state)5函数中分配了内存,但退出时没有释放它这肯定是由于粗心造成的,每个开发人员都知道这是错误,但据出去开局的开发人员讲,在我们的正式软件版本中确确实实发现过这种事情。比如在某个函数中,一开始分配了一块内存,

在函数处理过程中,有个出错后返回的处理,若此返回没有释放所分配的内存,那么在这儿就留下了一个隐患。下面举几种常见的内存泄漏错误:1.函数有多个出口时,没有在每个出口处对动态申请的内存进行释放。一般在异常处理时容易出现这种错误

。例:pRecord=newchar[pTable->GetRecordLength()];assert(pRecord!=NULL);if(pTable->GoTop(FALSE)!=DBIERR_NO

NE)return;//如果从这里返回,pRecord将得不到释放2.给指针赋值时,没有检查指针是否为空,如果指针不为空,那么指针原来指向的内存将丢失。如:structFileInfo*pdbffile=newstructFileInfo;pdbffile->pfileinfo=n

ewstructffblk;pdbffile->srcname=srcRootPath;pdbffile->desname=desRootPath;pdbffile->prev=NULL;pfile=pdbffile;赋值之前没有检查一下pfile是否为空,如果不为空,会造成pfile指向

的内存丢失。3.连续二次内存动态分配,在第二次分配失败时,忘记释放第一次已经申请到的内存。....pMsgDB_DEV=(PDBDevMsg)GetBuff(sizeof(DBDevMsg),__LINE__);

if(pMsgDB_DEV==NULL)return;pMsgDBApp_To_Logic=(LPDBSelfMsg)GetBuff(sizeof(DBSelfMsg),__LINE__);if(pMs

gDBApp_To_Logic==NULL)return;//此处返回造成pMsgDB_DEV指向的内存丢失4.代码中缺少应有的条件分支处理,导致程序未执行任何操作而退出时,也可能没有释放应释放的内存,这

种情况一般是缺少应有的else分支,或switch语句的default分支没有应有的处理。staticvoidOncePowerCmdHandle(structHT_Appmsg*msg){pPower_test

_answer=(struct_oncepower_test_answer*)GetBuff(sizeof(struct_oncepower_test_answer),__LINE__);if(pPower_

test_answer==NULL_PTR)return;......if(TSS_State[testpsn].state==TEST_DEV_BUSY||TSS_State[testpsn].state==TEST_DEV_ERROR){...}el

seif(TSS_State[testpsn].state==TEST_DEV_IDLE){...}//缺少else分支,可能造成pPower_test_answer得不到释放}6差1错误此类错误一般是由于把"<="写成"<"或">="写成">"等造

成的,由此引起的后果,很多情况下是很严重的,所以编程时,一定要在这些地方万分小心。7使用已释放的内存在程序中引用已经释放了的内存。8数据上溢或下溢,数组的越界等如:假设size为unsignedchar类型变量,那么while(size-->=0){...//pro

gram}将出现下溢,因为当size等于0时,再减1后不会小于0,而是0xFF,所以程序实际上是一个死循环。voidCell_CBCH_Load_Static(structMsgCBFAR*pMsg){。

。。memcpy((_UC*)&tmp_msg,pMsg,sizeof(tmp_msg));pMsg=pMsg+sizeof(tmp_msg);//sizeof(tmp_msg)=10;本意是想移动10个字节,可是实际上指针移动了10*sizeof(struct

MsgCB)个字节;CellNum=tmp_msg.usCellNum;。。。}所以结构指针传入函数后,如要进行指针移动操作,最好先将其转化为_UC型再说。总之指针操作要小心为上。9运算符优先级错误如"word=high<<8+low;"语句本意是

把字节high与low合成一个字,但由于"<<"比"+"优先级低,故结果不对。应改成如下之一:word=high<<8|low;word=high*256+low;word=(high<<8)+low;10编写非单

一功能的函数先看一下C运行库手册中一个函数的描述void*realloc(void*block,size_tsize);DescriptionReallocatesmainmemory.reallocattemptstoshrinkor

expandthepreviouslyallocatedblocktosizebytes.Ifsizeiszero,thememoryblockisfreedandNULLisreturned.Theblockargumentpointstoamemoryblockpreviouslyobtain

edbycallingmalloc,calloc,orrealloc.IfblockisaNULLpointer,reallocworksjustlikemalloc.reallocadjuststhesizeoftheallocatedblocktosize,copyingtheco

ntentstoanewlocationifnecessary.ReturnValuereallocreturnstheaddressofthereallocatedblock,whichcanbedifferentthantheaddressoftheoriginalblock.I

ftheblockcannotbereallocated,reallocreturnsNULL.Ifthevalueofsizeis0,thememoryblockisfreedandreallocreturnsNULL.看看re

alloc是不是一个实现得面面俱到的最好例子?它在一个函数中完成了所有的内存管理工作。既然如此,还要malloc干什么?还要free干什么?realloc全包了。有几个很好的理由说明我们不应该这样设计函数。首先,这样的函数很难指望程序员安全地使用。它包括了如此之多的

细节,甚至许多有经验的程序员都不全知道。另一个问题是:我们知道传递给realloc的可能是无用信息,但是因为其定义如此通用使它很难防范无效的参数。如果错误地给它传递了NULL指针,合法;如果错误地给它传递了为零的块长,也合法。如果实际上任何参数都合法,那么我们怎样用断言检查其参数的有效性呢?甚至在

极端的情况下也是如此,一个极端是释放内存块,另一个极端是分配内存块。这是两种截然相反的两种功能。产生多功能的函数几乎总是两个原因:一个是其多种功能是逐步演变而来的;另一个是具体的实现为其增加了多余的功能,为不包括这

些所谓的"幸运"功能,实现该函数的程序员扩展了相应的形式描述。但不管出于什么理由编写了多功能的函数,都要把它分解为不同的功能。这里有一个重要的原则:不要编写多种功能集于一身的函数。为了对参数进行更强的确认,要编写功能单一的函数。12不同数据类型之间的比较操作在循环终止条件的判断中,不同类型

变量的比较操作容易造成死循环。inti;...for(i=1;i<dwLen/2;i++){wCheckSum^=(*pCheck);pCheck++;}return(wCheckSum);该段代码是在DOS环境下用BC编

译的,循环变量i是int型(2个字节),而dwLen是DWORD型(4个字节),如果dwLen大于65536,那么该函数就是死循环了。11、公共资源的互斥性和竞用性例:测试板间通信性能。从接口板A向接口板B

循环发送消息,通过超级终端观察消息的收发情况。测试结果:每发送一定数量的消息帧后,会出现发送地址出错现象。原因:接收板回送缓冲区指针给发送板,是采用memcpy单字节拷贝的方式。若发送速度快于接收速度,两板

竞用发送板系统总线访问缓冲区指针所在的共享内存,导致数据访问冲突。memcpy过程被打断,即出现发送板读发送地址出错现象。采用四字节拷贝函数bcopyLongs传送发送缓冲区指针,问题解决。Theend

小橙橙
小橙橙
文档分享,欢迎浏览!
  • 文档 25747
  • 被下载 7
  • 被收藏 0
相关资源
广告代码123
若发现您的权益受到侵害,请立即联系客服,我们会尽快为您处理。侵权客服QQ:395972555 (支持时间:9:00-21:00) 公众号
Powered by 太赞文库
×
确认删除?