软件编程规范培训实例与练习模板.doc
《软件编程规范培训实例与练习模板.doc》由会员分享,可在线阅读,更多相关《软件编程规范培训实例与练习模板.doc(106页珍藏版)》请在咨信网上搜索。
软件编程规范培训实例与练习 106 资料内容仅供参考,如有不当或者侵权,请联系本人改正或者删除。 软件编程规范培训实例与练习 问题分类 1 逻辑类问题( A类) -指设计、 编码中出现的计算正确性和一致性、 程序逻辑控制等方面出现的问题, 在系统中起关键作用, 将导致软件死机、 功能正常实现等严重问题; 接口类问题( B类) -指设计、 编码中出现的函数和环境、 其它函数、 全局/局部变量或数据变量之间的数据/控制传输不匹配的问题, 在系统中起重要作用, 将导致模块间配合失效等严重问题; 维护类问题( C类) -指设计、 编码中出现的对软件系统的维护方便程度造成影响的问题, 在系统中不起关键作用, 但对系统后期维护造成不便或导致维护费用上升; 可测试性问题( 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) 当D≥3时, 如果P≥3%, 将进行警告处理, 并予以公告; 2) 当D≥5时, 如果P≥5%, 将进行罚款处理, 并予以公告。 目 录 一、 逻辑类代码问题 第5页 1、 变量/指针在使用前就必须初始化 第5页 【案例1.1.1】 第5页 2、 防止指针/数组操作越界 第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、 引用已释放的资源 第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页 【案例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】 第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 ); ... ... 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中就是这样) , 至少也是被限制使用。而在我们交换机的程序中大量使用指针, 而且有增无减。 2、 防止指针/数组操作越界 【案例1.2.1】 在香港项目测试中, 发现ISDN话机拨新业务号码时, 若一位一位的拨至18位, 不会有问题。但若先拨完号码再成组发送, 会导致MPU死机。 处理过程: 查错过程很简单, 按呼叫处理的过程检查代码, 发现某一处的判断有误, 本应为小于18的判断, 写成了小于等于18。 结 论: 代码编写有误。 思考与启示: 1、 极限测试必须注意, 测试前应对某项设计的极限做好充分测试规划。 2、 测试极限时还要注意多种业务接入点, 本例为ISDN。对于交换机来说, 任何一种业务都要分别在模拟话机、 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群计费计次表话单出中继群号不正确, 其它群的计次表中出中继群号正常。 处理过程: 与开发人员在测试组环境多次重复以上步骤, 发现11群的计次表话单有时正常, 有时其出中继群号就为一个随机值, 发生异常的频率比较高。为什么其它群的话单正常, 唯独11群不正常呢? 11群是四个群中最小的群, 其中继计次表位于缓冲区的首位, 打完电话后查询内存发现出中继群号在内存中是正确的, 取完话单后再查就不正确了。 结 论: 话单池的一个备份指针Pool_head_1和中继计次表的头指针重合, 影响到第一个中继计次表的计费。 思考与启示: 随机值的背后往往隐藏着指针问题, 两块内存缓冲区的交界处比较容易出现问题, 在编程时是应该注意的地方。 【案例1.2.3】 【正 文】 在接入网产品A测试中, 在内存数据库正常的情况下的各种数据库方面的操作都是正常的。为了进行数据库异常测试, 于是将数据库内容人为地破坏了。发现在对数据库进行比较操作时, 出现程序跑死了现象。 经过跟踪调试发现问题出现在如下一段代码中: 1 for(i=0; i<pSysHead->dbf_count; i++) 2 { 3 pDBFat = (_NM_DBFAT_STRUC *)(NVDB_BASE + DBFAT_OFFSET + i*DBFAT_LEN); 4 if(fat_check(pDBFat) != 0) 5 { 6 pSysHead->system_flag = 0; 7 head_sum(); 8 continue; 9 } 10 if(strlen(dbf->dbf_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, 该值是从被破坏的内存数据库中获取的, 正常情况下该值小于127。而pDBFat是数据库的起始地址, 如果pSysHead->dbf_count值异常过大, 将导致pDBFat值超过最大内存地址值, 随后进行的内存操作将导致内存操作越界错误, 因而在测试过程中数据库破坏后就出现了主机死机的现象。 上面的问题解决起来很容易, 只需在第一行代码中增加一个判断条件即可, 如下: for(i=0; i<pSysHead->dbf_coun && i < MAX_DB_NUM; i++) // MAX_DB_NUM=127 这样就保证了循环变量i的值在正常范围内, 从而避免了对指针pDBFat进行内存越界的操作。 从上面的测试过程中, 我们能够看到: 如此严重的问题, 仅仅是一个简单的错误引起的。实际上, 系统的不稳定往往是由这些看似很简单的小错误导致的。这个问题给我们教训的是: 在直接对内存地址进行操作时, 一定要保证其值的合法性, 否则容易引起内存操作越界, 给系统的稳定性带来潜在的威胁。 【案例1.2.4】 近日在CDB并行测试中发现一个问题: 我们需要的小区负荷话统结果总是为零, 开始还以为小区负荷太小, 于是加大短消息下发数量, 但还为零, 于是在程序中加入测试代码, 把收到的数据在BAM上打印出来, 结果打印出来的数据正常,不可能为零,仔细查看相关代码,问题只可能在指针移位上有问题,果然在函数中发现一处比较隐蔽的错误。 /* 功能:一个BM模块内所有小区CDB侧广播消息忙闲情况 */ /*************************************************************/ void Cell_CBCH_Load_Static(struct MsgCB FAR *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; 。。。 } 1 因此结构指针传入函数后, 如要进行指针移动操作, 最好先将其转化为_UC型再说。总之指针操作要小心为上。 3、 避免指针的非法引用 【案例1.3.1】 【正 文】 在一次测试中, 并没有记得做了什么操作, 发现HONET系统的主机复位了, 之后, 系统又工作正常了。由于没有打开后台的跟踪窗口, 当时查了半天没有眉目。过了半天, 现象又出现了, 而且这次是主机在重复复位, 系统根本无法正常工作了。 我凭记忆, 判断应该是与当时正在测试的DSL板的端口配置有关。于是将板上所有端口配置为普通2B+D端口, 重新加载在主机数据, 现象消失。于是初步定位为主机在DSL端口处理过程中有重大错误。 我在新的数据上努力恢复原出问题的现象, 却一直没有重现, 于是恢复原数据, 加载后立即重现。并注意到, 当DSL端口激活时, 主机复位。仔细比较两种数据的差别, 发现出现主机复位问题的数据中DSL板配置了MNT/MLT端口, 可是没有做DSL端口之间的半永久数据。 于是在程序中不断加打印语句, 经过后台的DBWIN调试程序跟踪, 最后终于定位为: 每当执行到portdsl.c的DeviceDslMsgProc()函数中处理U口透传的 if ( SPC_STATE_OK == pSpcCB->bySpcState ) 语句时, 主机复位。可是该语句似乎并无不妥。 再分析整个函数, pSpcCB在函数前部分已经被赋值, pSpcCB = SpcCB + (PortTable+index)->spcNo; 但由于得到 index 后, 没有任何判断, 导致若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 ) {。。。} } 修改后, 问题不再重现。 经过分析能够发现, 编译环境是有很大的容许空间的, 若主机没有做充分的保护, 很可能会有极严重的随即故障出现。因此编程时一定要考虑各种可能情况; 而测试中遇到此类死机问题, 则要耐心的定位到具体是执行哪句代码时出现的, 再进行分析。因为问题很隐蔽, 直接分析海一样的代码是很难发现的。 4、 变量类型定义错误 【案例1.4.1】 【正 文】 在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的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的恢复情况, 发现PVC能够正确恢复; ( 2) 再建PVC, DLCI=65536, 然后保存, 重起MUX, 观察PVC的恢复情况, 此时PVC不能正确恢复。 至此基本能够断定原因就是出在这里。带着这个目的查看原代码, 发现在以下代码中有问题: int _GetFrDlci( DWORD* dwDlci, char* str, DWORD dwDlciType, DWORD dwPortType, DWORD dwSlotID, DWORD dwPortID) { DWORD tempDlci; char szArg[80]; 1 char szLine[80]; ID LowPVCEP; DWORD dwDlciVal[5][2] = { {16,1007}, {16,1007}, {1024,64511}, {2048,129023}, {131072,4194303} } ; ... } typedef struct tagFrPppIntIWF { ... WORD wHdlcPort; WORD wHdlcDlci; WORD wPeerHdlcDlci; WORD wPeerOldAtmPort; ... } SFrPppIntIWFData; DWORD SaveFrNetIntIWFData ( DWORD *pdwWritePoint ) { BYTE bSlotID, bPeerSlotID; DWORD dwCCID, dwPeerCCID; WORD wHdlcPort, wAtmPort, wIci, wPeerIci, wPeerHdlcPort ; WORD wCount; ... } DWORD SaveFrNetExtIWFData ( DWORD *pdwWritePoint ) { BYTE bSlotID; DWORD dwCCID, dwPeerCCID; WORD wHdlcPort, wAtmPort, wIci ; WORD wCount; ... unSevData.FrNetExtIWF[wCount].bSlotID = bSlotID; unSevData.FrNetExtIWF[wCount].wHdlcPort = wHdlcPort; unSevData.FrNetExtIWF[wCount].wHdlcDlci = gFrPVCEP[bSlotID ][ gFrPVCC[bSlotID][dwCCID].dwLoPVCEP ].dwDLCI; unSevData.FrNetExtIWF[wCount].wOldAtmPort = wAtmPort; unSevData.FrNetExtIWF[wCount].wAtmDlci = gFrPVCEP[ bSlotID ][ gFrPVCC[bSlotID][dwCCID].dwHiPVCEP ].dwDLCI; unSevData.FrNetExtIWF[wCount].dwMapMode = gFrPVCC[bSlotID][dwCCID].dwMapMode; ... } DWORD RestoreFrNetExtIWFData ( WORD wSlotID, BYTE *pReadPoint ) { WORD wCount, wTotalNetIWF; BYTE bSlotID, bHdlcDlciType, bAtmDlciType; WORD wOldAtmPort, wAtmDlci, wHdlcPort, wHdlcDlci; DWORD dwMapMode, dwCIR, dwBe; DWORD dwCCID, dwResult, dwAtmPort; wTotalNetIWF = g_MuxData.SevDataSize.wFrNetExtIWFNum; ... } DWORD RestoreFrHdlcIntIWFData ( WORD wSlotID, BYTE *pReadPoint ) { WORD wCount, wTotalHdlcIWF; DWORD dwCCID, dwPeerCCID, dwAtmPort, dwPeerAtmPort; DWORD dwResult; BYTE bSlotID, bPeerSlotID; WORD wHdlcPort, wOldAtmPort, wCIR; WORD wPeerHdlcPort, wPeerOldAtmPort; ... } 其中涉及DLCI值的变量都为WORD( 即无符号短整型) 类型, 在程序的处理时, 出现WORD和DWORD( 无符号长整型) 类型在一句中同时存在的情况, 至此能够判断问题出在这里。由于DLCI值在不同类型时的取值范围不同, 前三种类型的取值范围为16~991, 第四种取值范围为2048~126975, 第五种取值范围为131072~4194303, 因此当采用前三种DLCI类型时, 采用WORD类型最大值为65535, 已经完全够用了; 而对于第四种类型时, 其取值在超过65535时, 获取DLCI值的函数_GetFrDlci( ) 采用DWORD类型, 而负责保存和恢复的两个函数SaveFrNetExtIWFData( ) 和RestoreFrNetExtIWFData( ) , 都把DLCI的值当作WORD类型进行处理, 因此导致DLCI取值越界, 于是程序把原本为长整型的DLCI强制转换成整型, 从而导致DLCI值在恢复时, 比原数据小65536。而在程序运行过程中, 这些数据保存在DRAM中, 程序运行直接从DRAM中获取数据, 程序不会出错; 当FRI板复位或插拔后, 需要从FLASH中读取数据, 此时恢复函数的错误就表现出来。 另一个问题是为什么23/4类型的DLCI数据不能恢复? 这是由于对于23/4类型的PVC, 其DLCI的取值范围为: 131072~4194303, 而程序强制转换并恢复的数据最大只能是65535, 因此这条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的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的恢复情况, 发现PVC能够正确恢复; ( 2) 再建PVC, DLCI=65536, 然后保存, 重起MUX, 观察PVC的恢复情况, 此时PVC不能正确恢复。 至此基本能够断定原因就是出在这里。带着这个目的查看原代码, 发现在以下代码中有问题: int _GetFrDlci( DWORD* dwDlci, char* str, DWORD dwDlciType, DWORD dwPortType, DWORD dwSlotID, DWORD dwPortID) { DWORD tempDlci; char szArg[80]; char szLine[80]; ID LowPVCEP; DWORD dwDlciVal[5][2] = { {16,1007}, {16,1007}, {1024,64511}, {2048,129023}, {131072,4194303} } ; ... } typedef struct tagFrPppIntIWF { ... WORD wHdlcPort; WORD wHdlcDlci; WORD wPeerHdlcDlci; WORD wPeerOldAtmPort; ... } SFrPppIntIWFData; DWORD SaveFrNetIntIWFData ( DWORD *pdwWritePoint ) { BYTE bSlotID, bPeerSlotID; DWORD dwCCID, dwPeerCCID; WORD wHdlcPort, wAtmPort, wIci, wPeerIci, wPeerHdlcPort ; WORD wCount; ... } DWORD SaveFrNetExtIWFData ( DWORD *pdwWritePoint ) { BYTE bSlotID; DWORD dwCCID, dwPeerCCID; WORD wHdlcPort, wAtmPort, wIci ; WORD wCount; ... unSevData.FrNetExtIWF[wCount].bSlotID = bSlotID; unSevData.FrNetExtIWF[wCount].wHdlcPort = wHdlcPort; unSevData.FrNetExtIWF[wCount].wHdlcDlci = gFrPVCEP[bSlotID ][ gFrPVCC[bSlotID][dwCCID].dwLoPVCEP ].dwDLCI; unSevData.FrNetExtIWF[wCount].wOldAtmPort = wAtmPort; unSevData.FrNetExtIWF[wCount].wAtmDlci = gFrPVCEP[ bSlotID ][ gFrPVCC[bSlotID][dwCCID].dwHiPVCEP ].dwDLCI; unSevData.FrNetExtIWF[wCount].dwMapMode = gFrPVCC[bSlotID][dwCCID].dwMapMode; ... } DWORD RestoreFrNetExtIWFData ( WORD wSlotID, BYTE *pReadPoint ) { WORD wCount, wTotalNetIWF; BYTE bSlotID, bHdlcDlciType, bAtmDlciType; WORD wOldAtmPort, wAtmDlci, wHdlcPort, wHdlcDlci; DWORD dwMapMode, dwCIR, dwBe; DWORD dwCCID, dwResult, dwAtmPort; wTotalNetIWF = g_MuxData.SevDataSize.wFrNetExtIWFNum; ... } DWORD RestoreFrHdlcIntIWFData ( WORD wSlotID, BYTE *pReadPoint ) { WORD wCount, wTotalHdlcIWF; DWORD dwCCID, dwPeerCCID, dwAtmPort, dwPeerAtmPort; DWORD dwResult; BYTE bSlotID, bPeerSlotID; WORD wHdlcPort, wOldAtmPort, wCIR; WORD wPeerHdlcPort, wPeerOldAtmPort; ... } 其中涉及DLCI值的变量都为WORD( 即无符号短整型) 类型, 在程序的处理时, 出现WORD和DWORD( 无符号长整型) 类型在一句中同时存在的情况, 至此能够判断问题出在这里。由于DLCI值在不同类型时的取值范围不同, 前三种类型的取值范围为16~991, 第四种取值范围为2048~126975, 第五种取值范围为131072~4194303, 因此当采用前三种DLCI类型时, 采用WORD类型最大值为65535, 已经完全够用了; 而对于第四种类型时, 其取值在超过65535时, 获取DLCI值的函数_GetFrDlci( ) 采用DWORD类型, 而负责保存和恢复的两个函数SaveFrNetExtIWFData( ) 和RestoreFrNetExtIWFData( ) , 都把DLCI的值当作WORD类型进行处理, 因此导致DLCI取值越界, 于是程序把原本为长整型的DLCI强制转换成整型, 从而导致DLCI值在恢复时, 比原数据小65536。而在程序运行过程中, 这些数据保存在DRAM中, 程序运行直接从DRAM中获取数据, 程序不会出错; 当FRI板复位或插拔后, 需要从FLASH中读取数据, 此时恢复函数的错误就表现出来。 另一个问题是为什么23/4类型的DLCI数据不能恢复? 这是由于对于23/4类型的PVC, 其DLCI的取值范围为: 131072~4194303, 而程序强制转换并恢复的数据最大只能是65535, 因此这条PVC不能恢复。 至此, DLCI数据恢复出错的原因完全找到, 解决的方法是将DLCI的类型改为DWORD类型。从这个案例能够看出, 在程序开发中一个很低级的错误, 将在实际工作中造成很严重的后果。 5、 正确使用逻辑与&&、 屏蔽&操作符 【案例1.5.1】 【案例描述】: 由于C语言中位与比求模效率高, 因而系统设计时, 对于模128的地方都改为与127, 系统定义的宏为#define MOD128 127和#define W_MOD 127(定义的宏的名字易引起误解), 但实际程序中还是采取求模, 从而引起发送窗口欲重发的和实际重发的不一致, 最终导致链路复位此类严重问题, 曾在定位此问题时花了不少时间。 【处理过程】: 处理过程如下: #define MOD128 127 //队列长128, 当队头到128时, 上其返回。 #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 = (LinkState[logic_link].Vs + MOD128 - (_UC)n_r) % MOD128 ; w_head = (LinkState[logic_link].SendWin.head + W_MOD - retran_num) % W_MOD ; 第一个语句求欲重发的消息包个数, 第二个语句求重发的起始位置, 当Vs小于n_r时, 将造成实际重发数小于欲重发数, 同时造成实际起始重发位置和欲重发起始位置错开, 从而引起链路复位。上面三个语句应该做如下改动: linkstate_ptr->SendWin.head = (head + 1) & W_MOD ; retran_num = (LinkState[logic_link].Vs + MOD128 + 1 - (_UC)n_r) & MOD128 ; w_head = (LinkState[logic_link].SendWin.head + W_MOD + 1 - retran_num) & W_MOD ; 【结 论】: 由于链路通信对系统效率要求很高, 算法采用效率最高的, 但位与( &) 和求模( %) 这小小的区别, 造成的竟是链路复位这种严重的错误。 【思考与启示】: 对这类问题, 大家在阅读代码或代码审查时一定要注意, 仔细一点往往能发现问题, 但在测试中来定位这种问题, 花费的时间往往更长。 6、 注意数据类- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 软件 编程 规范 培训 实例 练习 模板
咨信网温馨提示:
1、咨信平台为文档C2C交易模式,即用户上传的文档直接被用户下载,收益归上传人(含作者)所有;本站仅是提供信息存储空间和展示预览,仅对用户上传内容的表现方式做保护处理,对上载内容不做任何修改或编辑。所展示的作品文档包括内容和图片全部来源于网络用户和作者上传投稿,我们不确定上传用户享有完全著作权,根据《信息网络传播权保护条例》,如果侵犯了您的版权、权益或隐私,请联系我们,核实后会尽快下架及时删除,并可随时和客服了解处理情况,尊重保护知识产权我们共同努力。
2、文档的总页数、文档格式和文档大小以系统显示为准(内容中显示的页数不一定正确),网站客服只以系统显示的页数、文件格式、文档大小作为仲裁依据,个别因单元格分列造成显示页码不一将协商解决,平台无法对文档的真实性、完整性、权威性、准确性、专业性及其观点立场做任何保证或承诺,下载前须认真查看,确认无误后再购买,务必慎重购买;若有违法违纪将进行移交司法处理,若涉侵权平台将进行基本处罚并下架。
3、本站所有内容均由用户上传,付费前请自行鉴别,如您付费,意味着您已接受本站规则且自行承担风险,本站不进行额外附加服务,虚拟产品一经售出概不退款(未进行购买下载可退充值款),文档一经付费(服务费)、不意味着购买了该文档的版权,仅供个人/单位学习、研究之用,不得用于商业用途,未经授权,严禁复制、发行、汇编、翻译或者网络传播等,侵权必究。
4、如你看到网页展示的文档有www.zixin.com.cn水印,是因预览和防盗链等技术需要对页面进行转换压缩成图而已,我们并不对上传的文档进行任何编辑或修改,文档下载后都不会有水印标识(原文档上传前个别存留的除外),下载后原文更清晰;试题试卷类文档,如果标题没有明确说明有答案则都视为没有答案,请知晓;PPT和DOC文档可被视为“模板”,允许上传人保留章节、目录结构的情况下删减部份的内容;PDF文档不管是原文档转换或图片扫描而得,本站不作要求视为允许,下载前自行私信或留言给上传者【快乐****生活】。
5、本文档所展示的图片、画像、字体、音乐的版权可能需版权方额外授权,请谨慎使用;网站提供的党政主题相关内容(国旗、国徽、党徽--等)目的在于配合国家政策宣传,仅限个人学习分享使用,禁止用于任何广告和商用目的。
6、文档遇到问题,请及时私信或留言给本站上传会员【快乐****生活】,需本站解决可联系【 微信客服】、【 QQ客服】,若有其他问题请点击或扫码反馈【 服务填表】;文档侵犯商业秘密、侵犯著作权、侵犯人身权等,请点击“【 版权申诉】”(推荐),意见反馈和侵权处理邮箱:1219186828@qq.com;也可以拔打客服电话:4008-655-100;投诉/维权电话:4009-655-100。
1、咨信平台为文档C2C交易模式,即用户上传的文档直接被用户下载,收益归上传人(含作者)所有;本站仅是提供信息存储空间和展示预览,仅对用户上传内容的表现方式做保护处理,对上载内容不做任何修改或编辑。所展示的作品文档包括内容和图片全部来源于网络用户和作者上传投稿,我们不确定上传用户享有完全著作权,根据《信息网络传播权保护条例》,如果侵犯了您的版权、权益或隐私,请联系我们,核实后会尽快下架及时删除,并可随时和客服了解处理情况,尊重保护知识产权我们共同努力。
2、文档的总页数、文档格式和文档大小以系统显示为准(内容中显示的页数不一定正确),网站客服只以系统显示的页数、文件格式、文档大小作为仲裁依据,个别因单元格分列造成显示页码不一将协商解决,平台无法对文档的真实性、完整性、权威性、准确性、专业性及其观点立场做任何保证或承诺,下载前须认真查看,确认无误后再购买,务必慎重购买;若有违法违纪将进行移交司法处理,若涉侵权平台将进行基本处罚并下架。
3、本站所有内容均由用户上传,付费前请自行鉴别,如您付费,意味着您已接受本站规则且自行承担风险,本站不进行额外附加服务,虚拟产品一经售出概不退款(未进行购买下载可退充值款),文档一经付费(服务费)、不意味着购买了该文档的版权,仅供个人/单位学习、研究之用,不得用于商业用途,未经授权,严禁复制、发行、汇编、翻译或者网络传播等,侵权必究。
4、如你看到网页展示的文档有www.zixin.com.cn水印,是因预览和防盗链等技术需要对页面进行转换压缩成图而已,我们并不对上传的文档进行任何编辑或修改,文档下载后都不会有水印标识(原文档上传前个别存留的除外),下载后原文更清晰;试题试卷类文档,如果标题没有明确说明有答案则都视为没有答案,请知晓;PPT和DOC文档可被视为“模板”,允许上传人保留章节、目录结构的情况下删减部份的内容;PDF文档不管是原文档转换或图片扫描而得,本站不作要求视为允许,下载前自行私信或留言给上传者【快乐****生活】。
5、本文档所展示的图片、画像、字体、音乐的版权可能需版权方额外授权,请谨慎使用;网站提供的党政主题相关内容(国旗、国徽、党徽--等)目的在于配合国家政策宣传,仅限个人学习分享使用,禁止用于任何广告和商用目的。
6、文档遇到问题,请及时私信或留言给本站上传会员【快乐****生活】,需本站解决可联系【 微信客服】、【 QQ客服】,若有其他问题请点击或扫码反馈【 服务填表】;文档侵犯商业秘密、侵犯著作权、侵犯人身权等,请点击“【 版权申诉】”(推荐),意见反馈和侵权处理邮箱:1219186828@qq.com;也可以拔打客服电话:4008-655-100;投诉/维权电话:4009-655-100。
关于本文