收藏 分销(赏)

软件编程规范培训实例与练习模板.doc

上传人:快乐****生活 文档编号:4479621 上传时间:2024-09-24 格式:DOC 页数:106 大小:322.50KB
下载 相关 举报
软件编程规范培训实例与练习模板.doc_第1页
第1页 / 共106页
软件编程规范培训实例与练习模板.doc_第2页
第2页 / 共106页
软件编程规范培训实例与练习模板.doc_第3页
第3页 / 共106页
软件编程规范培训实例与练习模板.doc_第4页
第4页 / 共106页
软件编程规范培训实例与练习模板.doc_第5页
第5页 / 共106页
点击查看更多>>
资源描述

1、软件编程规范培训实例与练习106资料内容仅供参考,如有不当或者侵权,请联系本人改正或者删除。软件编程规范培训实例与练习 问题分类1 逻辑类问题( A类) 指设计、 编码中出现的计算正确性和一致性、 程序逻辑控制等方面出现的问题, 在系统中起关键作用, 将导致软件死机、 功能正常实现等严重问题; 接口类问题( B类) 指设计、 编码中出现的函数和环境、 其它函数、 全局/局部变量或数据变量之间的数据/控制传输不匹配的问题, 在系统中起重要作用, 将导致模块间配合失效等严重问题; 维护类问题( C类) 指设计、 编码中出现的对软件系统的维护方便程度造成影响的问题, 在系统中不起关键作用, 但对系统

2、后期维护造成不便或导致维护费用上升; 可测试性问题( D类) 指设计、 编码中因考虑不周而导致后期系统可测试性差的问题。 处罚办法 问题发生率: P=D/S D=DA+0.5DB+0.25DC 其中: P 问题发生率 D 1个季度内错误总数 DA 1个季度内A类错误总数 DB 1个季度内B类错误总数 DC 1个季度内C类错误总数 S 1个季度内收到问题报告单总数 1) 当D3时, 如果P3, 将进行警告处理, 并予以公告; 2) 当D5时, 如果P5, 将进行罚款处理, 并予以公告。目 录一、 逻辑类代码问题第5页1、 变量/指针在使用前就必须初始化第5页【案例1.1.1】第5页2、 防止指针

3、/数组操作越界第5页【案例1.2.1】第5页【案例1.2.2】第6页【案例1.2.3】第7页【案例1.2.4】第8页3、 避免指针的非法引用第9页【案例1.3.1】第9页4、 变量类型定义错误第10页【案例1.4.1】第10页5、 正确使用逻辑与&、 屏蔽&操作符第17页【案例1.5.1】第17页6、 注意数据类型的匹配第18页【案例1.6.1】第18页【案例1.6.2】第18页7、 用于控制条件转移的表示式及取值范围是否书写正确第20页【案例1.7.1】第20页【案例1.7.2】第21页【案例1.7.3】第22页8、 条件分支处理是否有遗漏第24页【案例1.8.1】第24页9、 引用已释放的

4、资源第26页【案例1.9.1】第26页10、 分配资源是否已正确释放第28页【案例1.10.1】第28页【案例1.10.2】第29页【案例1.10.3】第30页【案例1.10.4】第32页【案例1.10.5】第33页【案例1.10.6】第35页【案例1.10.7】第38页11、 防止资源的重复释放第39页【案例1.11.1】第39页12、 公共资源的互斥性和竞用性第40页【案例1.12.1】第40页【案例1.12.2】第40页二、 接口类代码问题第43页1、 对函数参数进行有效性检查第43页【案例2.1.1】第43页【案例2.1.2】第43页【案例2.1.3】第44页【案例2.1.4】第46页

5、【案例2.1.5】第47页【案例2.1.6】第48页2、 注意多出口函数的处理第49页【案例2.2.1】第49页三、 维护类代码问题第51页1、 统一枚举类型的使用第51页【案例3.1.1】第51页2、 注释量至少占代码总量的20第51页【案例3.2.1】对XXX产品BAM某版本部分代码注释量的统计第51页四、 产品兼容性问题第52页1、 系统配置、 命令方式第52页【案例4.1.1】第52页【案例4.1.2】第53页2、 设备对接第54页【案例4.2.1】第54页3、 其它第55页【案例4.3.1】第55页五、 版本控制问题第58页1、 新老代码中同一全局变量不一致第58页【案例5.1.1】

6、第58页六、 可测试性代码问题第59页1、 调试信息/打印信息的正确性第59页【案例6.1.1】第59页一、 逻辑类代码问题1、 变量/指针在使用前就必须初始化【案例1.1.1】C语言中最大的特色就是指针。指针的使用具有很强的技巧性和灵活性, 但同时也带来了很大的危险性。在XXX的代码中有如下一端对指针的灵活使用: . . _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

7、 );. . b_middle_data_ok = generate_trans_middle_data_from_original_data( puc_card_config_tab, Ul_card_config_num). .其中红色部分巧妙的利用指向指针的指针为指针puc_card_config_tab赋值,而在兰色部分使用该指针。但在Get_Config_Table函数中有可能失败返回而不给该指针赋值。因此, 以后使用的可能是一个非法指针。指针的使用是非常灵活的, 同时也存在危险性, 必须小心使用。指针使用的危险性举世共知。在新的编程思想中, 指针基本上被禁止使用( JAVA中就是这

8、样) , 至少也是被限制使用。而在我们交换机的程序中大量使用指针, 而且有增无减。2、 防止指针/数组操作越界【案例1.2.1】 在香港项目测试中, 发现ISDN话机拨新业务号码时, 若一位一位的拨至18位, 不会有问题。但若先拨完号码再成组发送, 会导致MPU死机。 处理过程: 查错过程很简单, 按呼叫处理的过程检查代码, 发现某一处的判断有误, 本应为小于18的判断, 写成了小于等于18。 结 论: 代码编写有误。思考与启示: 1、 极限测试必须注意, 测试前应对某项设计的极限做好充分测试规划。 2、 测试极限时还要注意多种业务接入点, 本例为ISDN。对于交换机来说, 任何一种业务都要分

9、别在模拟话机、 ISDN话机、 V5话机、 多种形式的话务台上做测试。对于中继的业务, 则要充分考虑各种信令: TUP、 ISUP、 PRA、 NO1、 V5等等。【案例1.2.2】对某交换类进行计费测试, 字冠011对应1号路由、 1号子路由, 有4个中继群11,12,13,14(都属于1#模块), 前后两个群分别构成自环。其中11,13群向为出中继,12,14群向为入中继, 对这四个群分别进行计费设置, 对出入中继都计费。电话60640001拨打两次, 使四个群都有机会被计费, 取话单后浏览话单发现对11群计费计次表话单出中继群号不正确, 其它群的计次表中出中继群号正常。处理过程: 与开发

10、人员在测试组环境多次重复以上步骤, 发现11群的计次表话单有时正常, 有时其出中继群号就为一个随机值, 发生异常的频率比较高。为什么其它群的话单正常, 唯独11群不正常呢? 11群是四个群中最小的群, 其中继计次表位于缓冲区的首位, 打完电话后查询内存发现出中继群号在内存中是正确的, 取完话单后再查就不正确了。结 论: 话单池的一个备份指针Pool_head_1和中继计次表的头指针重合, 影响到第一个中继计次表的计费。思考与启示: 随机值的背后往往隐藏着指针问题, 两块内存缓冲区的交界处比较容易出现问题, 在编程时是应该注意的地方。【案例1.2.3】【正 文】 在接入网产品A测试中, 在内存数

11、据库正常的情况下的各种数据库方面的操作都是正常的。为了进行数据库异常测试, 于是将数据库内容人为地破坏了。发现在对数据库进行比较操作时, 出现程序跑死了现象。经过跟踪调试发现问题出现在如下一段代码中: 1for(i=0; idbf_count; i+)23 pDBFat = (_NM_DBFAT_STRUC *)(NVDB_BASE + DBFAT_OFFSET + i*DBFAT_LEN);4if(fat_check(pDBFat) != 0) 56 pSysHead-system_flag = 0;7 head_sum();8 continue;9 10 if(strlen(dbf-dbf

12、_name) != 0 & strncmp(dbf-dbf_name, pDBFat-dbf_name, strlen(dbf-dbf_name) = 0)11 12 dbf_ptr1 = (_UC *)pDBFat-dbf_head;13 filesize = pDBFat-dbf_fsize;14 break;15 16 在测试时发现程序死在循环之中, 得到的错误记录是Bus Error( 总线出错) , 由此能够说明出现了内存操作异常。经过跟踪变量值发现循环变量i的阀值pSysHead-dbf_count的数值为0xFFFFFFFF, 该值是从被破坏的内存数据库中获取的, 正常情况下该值

13、小于127。而pDBFat是数据库的起始地址, 如果pSysHead-dbf_count值异常过大, 将导致pDBFat值超过最大内存地址值, 随后进行的内存操作将导致内存操作越界错误, 因而在测试过程中数据库破坏后就出现了主机死机的现象。上面的问题解决起来很容易, 只需在第一行代码中增加一个判断条件即可, 如下: for(i=0; idbf_coun & i bySpcState )语句时, 主机复位。可是该语句似乎并无不妥。再分析整个函数, pSpcCB在函数前部分已经被赋值, pSpcCB = SpcCB + (PortTable+index)-spcNo;但由于得到 index 后,

14、没有任何判断, 导致若MNT/MLT端口没有做半永久, 端口激活后, 执行此部分函数, (PortTable+index)-spcNo 有可能为NULL_WORD, 于是, 运算后, pSpcCB 可能为非法值。此时主机在取进行判断, 就不知会导致什么后果了。其实, 改起来很简单, 只要在这两句前增加一个判断就行了。于是, 修改代码为: if ( (PortTable+index)-spcNo != NULL_WORD)pSpcCB = SpcCB + (PortTable+index)-spcNo;if ( SPC_STATE_OK = pSpcCB-bySpcState )。修改后, 问题

15、不再重现。经过分析能够发现, 编译环境是有很大的容许空间的, 若主机没有做充分的保护, 很可能会有极严重的随即故障出现。因此编程时一定要考虑各种可能情况; 而测试中遇到此类死机问题, 则要耐心的定位到具体是执行哪句代码时出现的, 再进行分析。因为问题很隐蔽, 直接分析海一样的代码是很难发现的。4、 变量类型定义错误【案例1.4.1】【正 文】 在FRI板上建几条FRPVC, 其DLCI类型分别为: 10Bit/2bytes、 10bit/3bytes、 16bit/3bytes、 17bit/4bytes、 23bit/4bytes。相应的DLCI值为: 16、 234、 991、 12697

16、5、 1234567, 然后保存, 重起MUX, 观察PVC的恢复情况, 结果DLCI值为16、 234和991的PVC正确恢复, 而DLCI=126975的PVC恢复的数据错误为61439, 而DLCI=1234567的PVC完全没有恢复。 对于17/4类型, DLCI=126975的PVC在恢复时变成61439, 根据这条线索, 查找原因, 发现126975-61439=65535, 转化二进制就是00000, 也就是说在数据恢复或保存时把原数据的第一个1给忽略了。此时第一个想法是: 在程序处理中, 把无符号长整型变量当作短整型变量处理了, 为了证实这个判断, 针对17bit/4bytes

17、类型又重新设计测试用例: ( 1) 先建PVC, DLCI=65535, 然后保存, 重起MUX, 观察PVC的恢复情况, 发现PVC能够正确恢复; ( 2) 再建PVC, DLCI=65536, 然后保存, 重起MUX, 观察PVC的恢复情况, 此时PVC不能正确恢复。至此基本能够断定原因就是出在这里。带着这个目的查看原代码, 发现在以下代码中有问题: int_GetFrDlci( DWORD* dwDlci, char* str, DWORD dwDlciType, DWORD dwPortType, DWORD dwSlotID, DWORD dwPortID) DWORD tempDl

18、ci;charszArg80;1charszLine80;IDLowPVCEP; DWORDdwDlciVal52 = 16,1007, 16,1007, 1024,64511, 2048,129023, 131072,4194303 ; typedef struct tagFrPppIntIWFWORDwHdlcPort;WORDwHdlcDlci; WORDwPeerHdlcDlci; WORDwPeerOldAtmPort;SFrPppIntIWFData;DWORD SaveFrNetIntIWFData ( DWORD *pdwWritePoint )BYTEbSlotID, bPe

19、erSlotID;DWORDdwCCID, dwPeerCCID;WORDwHdlcPort, wAtmPort, wIci, wPeerIci, wPeerHdlcPort ;WORDwCount; DWORD SaveFrNetExtIWFData ( DWORD *pdwWritePoint )BYTEbSlotID;DWORDdwCCID, dwPeerCCID;WORDwHdlcPort, wAtmPort, wIci ;WORDwCount;unSevData.FrNetExtIWFwCount.bSlotID= bSlotID;unSevData.FrNetExtIWFwCoun

20、t.wHdlcPort= wHdlcPort;unSevData.FrNetExtIWFwCount.wHdlcDlci= gFrPVCEPbSlotID gFrPVCCbSlotIDdwCCID.dwLoPVCEP .dwDLCI;unSevData.FrNetExtIWFwCount.wOldAtmPort= wAtmPort;unSevData.FrNetExtIWFwCount.wAtmDlci= gFrPVCEP bSlotID gFrPVCCbSlotIDdwCCID.dwHiPVCEP .dwDLCI;unSevData.FrNetExtIWFwCount.dwMapMode =

21、 gFrPVCCbSlotIDdwCCID.dwMapMode; DWORD RestoreFrNetExtIWFData ( WORD wSlotID, BYTE *pReadPoint )WORDwCount, wTotalNetIWF;BYTEbSlotID, bHdlcDlciType, bAtmDlciType;WORDwOldAtmPort, wAtmDlci, wHdlcPort, wHdlcDlci; DWORDdwMapMode, dwCIR, dwBe;DWORDdwCCID, dwResult, dwAtmPort;wTotalNetIWF = g_MuxData.Sev

22、DataSize.wFrNetExtIWFNum;DWORD RestoreFrHdlcIntIWFData ( WORD wSlotID, BYTE *pReadPoint )WORDwCount, wTotalHdlcIWF;DWORDdwCCID, dwPeerCCID, dwAtmPort, dwPeerAtmPort;DWORDdwResult;BYTEbSlotID, bPeerSlotID;WORDwHdlcPort, wOldAtmPort, wCIR;WORDwPeerHdlcPort, wPeerOldAtmPort; 其中涉及DLCI值的变量都为WORD( 即无符号短整型

23、) 类型, 在程序的处理时, 出现WORD和DWORD( 无符号长整型) 类型在一句中同时存在的情况, 至此能够判断问题出在这里。由于DLCI值在不同类型时的取值范围不同, 前三种类型的取值范围为16991, 第四种取值范围为2048126975, 第五种取值范围为1310724194303, 因此当采用前三种DLCI类型时, 采用WORD类型最大值为65535, 已经完全够用了; 而对于第四种类型时, 其取值在超过65535时, 获取DLCI值的函数_GetFrDlci( ) 采用DWORD类型, 而负责保存和恢复的两个函数SaveFrNetExtIWFData( ) 和RestoreFrN

24、etExtIWFData( ) , 都把DLCI的值当作WORD类型进行处理, 因此导致DLCI取值越界, 于是程序把原本为长整型的DLCI强制转换成整型, 从而导致DLCI值在恢复时, 比原数据小65536。而在程序运行过程中, 这些数据保存在DRAM中, 程序运行直接从DRAM中获取数据, 程序不会出错; 当FRI板复位或插拔后, 需要从FLASH中读取数据, 此时恢复函数的错误就表现出来。 另一个问题是为什么23/4类型的DLCI数据不能恢复? 这是由于对于23/4类型的PVC, 其DLCI的取值范围为: 1310724194303, 而程序强制转换并恢复的数据最大只能是65535, 因

25、此这条PVC不能恢复。 至此, DLCI数据恢复出错的原因完全找到, 解决的方法是将DLCI的类型改为DWORD类型。从这个案例能够看出, 在程序开发中一个很低级的错误, 将在实际工作中造成很严重的后果。【案例1.4.2】【正 文】 在FRI板上建几条FRPVC, 其DLCI类型分别为: 10Bit/2bytes、 10bit/3bytes、 16bit/3bytes、 17bit/4bytes、 23bit/4bytes。相应的DLCI值为: 16、 234、 991、 126975、 1234567, 然后保存, 重起MUX, 观察PVC的恢复情况, 结果DLCI值为16、 234和991

26、的PVC正确恢复, 而DLCI=126975的PVC恢复的数据错误为61439, 而DLCI=1234567的PVC完全没有恢复。 对于17/4类型, DLCI=126975的PVC在恢复时变成61439, 根据这条线索, 查找原因, 发现126975-61439=65535, 转化二进制就是00000, 也就是说在数据恢复或保存时把原数据的第一个1给忽略了。此时第一个想法是: 在程序处理中, 把无符号长整型变量当作短整型变量处理了, 为了证实这个判断, 针对17bit/4bytes类型又重新设计测试用例: ( 1) 先建PVC, DLCI=65535, 然后保存, 重起MUX, 观察PVC的

27、恢复情况, 发现PVC能够正确恢复; ( 2) 再建PVC, DLCI=65536, 然后保存, 重起MUX, 观察PVC的恢复情况, 此时PVC不能正确恢复。至此基本能够断定原因就是出在这里。带着这个目的查看原代码, 发现在以下代码中有问题: int_GetFrDlci( DWORD* dwDlci, char* str, DWORD dwDlciType, DWORD dwPortType, DWORD dwSlotID, DWORD dwPortID) DWORD tempDlci;charszArg80;charszLine80;IDLowPVCEP; DWORDdwDlciVal52

28、 = 16,1007, 16,1007, 1024,64511, 2048,129023, 131072,4194303 ; typedef struct tagFrPppIntIWFWORDwHdlcPort;WORDwHdlcDlci; WORDwPeerHdlcDlci; WORDwPeerOldAtmPort;SFrPppIntIWFData;DWORD SaveFrNetIntIWFData ( DWORD *pdwWritePoint )BYTEbSlotID, bPeerSlotID;DWORDdwCCID, dwPeerCCID;WORDwHdlcPort, wAtmPort,

29、 wIci, wPeerIci, wPeerHdlcPort ;WORDwCount; DWORD SaveFrNetExtIWFData ( DWORD *pdwWritePoint )BYTEbSlotID;DWORDdwCCID, dwPeerCCID;WORDwHdlcPort, wAtmPort, wIci ;WORDwCount;unSevData.FrNetExtIWFwCount.bSlotID= bSlotID;unSevData.FrNetExtIWFwCount.wHdlcPort= wHdlcPort;unSevData.FrNetExtIWFwCount.wHdlcD

30、lci= gFrPVCEPbSlotID gFrPVCCbSlotIDdwCCID.dwLoPVCEP .dwDLCI;unSevData.FrNetExtIWFwCount.wOldAtmPort= wAtmPort;unSevData.FrNetExtIWFwCount.wAtmDlci= gFrPVCEP bSlotID gFrPVCCbSlotIDdwCCID.dwHiPVCEP .dwDLCI;unSevData.FrNetExtIWFwCount.dwMapMode = gFrPVCCbSlotIDdwCCID.dwMapMode; DWORD RestoreFrNetExtIWF

31、Data ( WORD wSlotID, BYTE *pReadPoint )WORDwCount, wTotalNetIWF;BYTEbSlotID, bHdlcDlciType, bAtmDlciType;WORDwOldAtmPort, wAtmDlci, wHdlcPort, wHdlcDlci; DWORDdwMapMode, dwCIR, dwBe;DWORDdwCCID, dwResult, dwAtmPort;wTotalNetIWF = g_MuxData.SevDataSize.wFrNetExtIWFNum;DWORD RestoreFrHdlcIntIWFData (

32、WORD wSlotID, BYTE *pReadPoint )WORDwCount, wTotalHdlcIWF;DWORDdwCCID, dwPeerCCID, dwAtmPort, dwPeerAtmPort;DWORDdwResult;BYTEbSlotID, bPeerSlotID;WORDwHdlcPort, wOldAtmPort, wCIR;WORDwPeerHdlcPort, wPeerOldAtmPort; 其中涉及DLCI值的变量都为WORD( 即无符号短整型) 类型, 在程序的处理时, 出现WORD和DWORD( 无符号长整型) 类型在一句中同时存在的情况, 至此能够判

33、断问题出在这里。由于DLCI值在不同类型时的取值范围不同, 前三种类型的取值范围为16991, 第四种取值范围为2048126975, 第五种取值范围为1310724194303, 因此当采用前三种DLCI类型时, 采用WORD类型最大值为65535, 已经完全够用了; 而对于第四种类型时, 其取值在超过65535时, 获取DLCI值的函数_GetFrDlci( ) 采用DWORD类型, 而负责保存和恢复的两个函数SaveFrNetExtIWFData( ) 和RestoreFrNetExtIWFData( ) , 都把DLCI的值当作WORD类型进行处理, 因此导致DLCI取值越界, 于是程

34、序把原本为长整型的DLCI强制转换成整型, 从而导致DLCI值在恢复时, 比原数据小65536。而在程序运行过程中, 这些数据保存在DRAM中, 程序运行直接从DRAM中获取数据, 程序不会出错; 当FRI板复位或插拔后, 需要从FLASH中读取数据, 此时恢复函数的错误就表现出来。 另一个问题是为什么23/4类型的DLCI数据不能恢复? 这是由于对于23/4类型的PVC, 其DLCI的取值范围为: 1310724194303, 而程序强制转换并恢复的数据最大只能是65535, 因此这条PVC不能恢复。 至此, DLCI数据恢复出错的原因完全找到, 解决的方法是将DLCI的类型改为DWORD类

35、型。从这个案例能够看出, 在程序开发中一个很低级的错误, 将在实际工作中造成很严重的后果。5、 正确使用逻辑与&、 屏蔽&操作符【案例1.5.1】【案例描述】: 由于C语言中位与比求模效率高, 因而系统设计时, 对于模128的地方都改为与127, 系统定义的宏为#define MOD128 127和#define W_MOD 127(定义的宏的名字易引起误解), 但实际程序中还是采取求模, 从而引起发送窗口欲重发的和实际重发的不一致, 最终导致链路复位此类严重问题, 曾在定位此问题时花了不少时间。【处理过程】: 处理过程如下: #define MOD128 127 /队列长128, 当队头到1

36、28时, 上其返回。#define W_MOD 127 /发送窗口队列, 意义同上。在函数L2_TO_L1()中, 有如下语句: linkstate_ptr-SendWin.head = (head + 1) % W_MOD ;这里当head=126时, SendWin.head = 0, 这将造成发送窗口指针和队列窗口指针错位, 造成链路复位;另外, 在重发函数void INVOKE_RETRANSMISSION(_US logic_link,_US n_r)中, 有如下语句: retran_num = (LinkStatelogic_link.Vs + MOD128 - (_UC)n_r)

37、 % MOD128 ; w_head = (LinkStatelogic_link.SendWin.head + W_MOD - retran_num) % W_MOD ;第一个语句求欲重发的消息包个数, 第二个语句求重发的起始位置, 当Vs小于n_r时, 将造成实际重发数小于欲重发数, 同时造成实际起始重发位置和欲重发起始位置错开, 从而引起链路复位。上面三个语句应该做如下改动: linkstate_ptr-SendWin.head = (head + 1) & W_MOD ; retran_num = (LinkStatelogic_link.Vs + MOD128 + 1 - (_UC)n_r) & MOD128 ; w_head = (LinkStatelogic_link.SendWin.head + W_MOD + 1 - retran_num) & W_MOD ;【结 论】: 由于链路通信对系统效率要求很高, 算法采用效率最高的, 但位与( &) 和求模( %) 这小小的区别, 造成的竟是链路复位这种严重的错误。【思考与启示】: 对这类问题, 大家在阅读代码或代码审查时一定要注意, 仔细一点往往能发现问题, 但在测试中来定位这种问题, 花费的时间往往更长。6、 注意数据类

展开阅读全文
相似文档                                   自信AI助手自信AI助手
猜你喜欢                                   自信AI导航自信AI导航
搜索标签

当前位置:首页 > 通信科技 > 其他

移动网页_全站_页脚广告1

关于我们      便捷服务       自信AI       AI导航        获赠5币

©2010-2024 宁波自信网络信息技术有限公司  版权所有

客服电话:4008-655-100  投诉/维权电话:4009-655-100

gongan.png浙公网安备33021202000488号   

icp.png浙ICP备2021020529号-1  |  浙B2-20240490  

关注我们 :gzh.png    weibo.png    LOFTER.png 

客服