软件编程规范培训实例与练习-cmmi(编辑修改稿)内容摘要:
ta ( DWORD *pdwWritePoint ) { BYTE bSlotID。 DWORD dwCCID, dwPeerCCID。 WORD wHdlcPort, wAtmPort, wIci。 WORD wCount。 ... [wCount].bSlotID = bSlotID。 [wCount].wHdlcPort = wHdlcPort。 [wCount].wHdlcDlci = gFrPVCEP[bSlotID ][ gFrPVCC[bSlotID][dwCCID].dwLoPVCEP ].dwDLCI。 [wCount].wOldAtmPort = wAtmPort。 [wCount].wAtmDlci = gFrPVCEP[ bSlotID ][ gFrPVCC[bSlotID][dwCCID].dwHiPVCEP ].dwDLCI。 [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 =。 ... } 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类型。 从这个案例可以看出,在程序开发中一个很低级的错误,将在实际工作中造成很严重的后果。 正确使用逻辑与 amp。 amp。 、屏蔽 amp。 操作符 【案例 】 【案例描述】:由于 C语言中位与比求模效率高,因而系统设计时,对于模 128的地方都改为与 127,系统定义的宏为 define MOD128 127和 define W_MOD 127(定义的宏的名字易引起误解 ),但实际程序中还是采取求模,从而引起发送窗口欲重发的和实际重发的不一致,最终导致链路复位此类严重问题,曾在定位此 问题时花了不少时间。 【处理过程】:处理过程如下: define MOD128 127 //队列长 128,当队头到 128时,上其返回。 define W_MOD 127 //发送窗口队列,意义同上。 在函数 L2_TO_L1()中,有如下语句: linkstate_ptr = (head + 1) % W_MOD。 这里当 head=126时, = 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]. + W_MOD retran_num) % W_MOD。 第一个语句求欲重发 的消息包个数,第二个语句求重发的起始位置,当 Vs小于n_r时,将造成实际重发数小于欲重发数,同时造成实际起始重发位置和欲重发起始位置错开,从而引起链路复位。 上面三个语句应该做如下改动: linkstate_ptr = (head + 1) amp。 W_MOD。 retran_num = (LinkState[logic_link].Vs + MOD128 + 1 (_UC)n_r) amp。 MOD128。 w_head = (LinkState[logic_link]. + W_MOD + 1 retran_num) amp。 W_MOD。 【结 论】:由于链路通信对系统效率要求很高,算法采用效率最高的,但位与( amp。 )和求模( %)这小小的区别,造成的竟是链路复位这种严重的错误。 【思考与启示】:对这类问题,大家在阅读代码或代码审查时一定要注意,仔细一点往往能发现问题,但在测试中来定位这种问题,花费的时间往往更长。 注意数据类型的匹配 【案例 】 【案例描述】 下面通过测试中的一个例子来说 明这个问题:命令 DSP N7C是用来显示 NO7电路状态的,其参数设备类型 DID支持 TUP和 ISUP,参数信道号 BSN支持多值输入(最多支持 32路查询),正常情况下该命令没有问题。 但试了非正常情况下,问题就出来了。 首先试 BSN参数越界情况,即参数 BSN超过 32路查询,选了几个数据段,问题就出来了。 对于 0amp。 amp。 300和 0amp。 amp。 256,该命令返回结果不一致,对前者认为参数越界,对后者返回执行成功。 对于参数 DID,选定一种设备类型( TUP或 ISUP),让参数 BSN所包含的32路电路跨越 TUP和 ISUP, 两次结果是不一致的。 【处理过程】 反馈到开发人员那里,第一个问题是 BAM的问题,第二个问题是 SM的问题。 【结 论】 为数据超出范围溢出造成, int值赋值给 BYTE,造成数据丢失。 问题的产生是因为查询的第一个信道是 TUP电路,但是却按 ISUP电路查询。 ISUP的维护处理函数判断第一个信道不是 ISUP信道,认为整个的 PCM不是ISUP类型的 PCM,返回全部的电路状态为未安装。 消息处理不合理。 TUP也会产生如此错误。 【思考与启示】 我们的 MML命令并不是无懈可击的,许多表面上的小问题, 往往隐藏着代码的缺陷和错误。 【案例 】 【正 文】 当我们使用 PCLINT检查代码时,会发现大量的数据类型不匹配的告警,大部分情况下,这种代码上存在的问题并不会引起程序功能实现上的错误,但有些情况下,也许会产生严重的问题: 一、不同数据类型变量之间赋值引起的问题,实际上,该类问题也可以分为几种情况: 直接赋值,比如,把一个 WORD型变量赋给一个 INT型变量,如果WORD型变量大于 32767, INT型变量得到的就是一个负值了。 【例一】一次测试过程中发 现, SDH送的告警在 BAM调试窗口打印出红色提示: File(XXX),Line(XXX):Invalid alarm id ,from: 7, AlarmId: 65463 经过检查数据发现,并没有 ID为 65463的告警,分析上报的数据帧,发现上报的告警 ID为 B7,原来代码中有一处强制类型转换: = (WORD)RecvBuffer[iTmpLen + 5]。 char型强制转换成 WORD型。 B7就变成了 FFB7,十进制就是 65463。 由于 char是有符号型, B7的第 8位为 1,所以转换后为 FFB7,而不是代码作者希望的 00B7,如果第 8位是 0,或该变量是 BYTE型,转换就不会有问题了。 函数形参和实参不一致,实际上和第一种情况本质上是一样的,只是表现的形式不太一样,这种情况也是代码中经常出现的问题 ,下面例子是测试中曾经发现的一个小问题: 【例二】在 file01中的 INT DebugMsgProc(char byMsg0, char byMsg1)函数,两个形参都是 char型,而实际传入的参数都是 BYTE型,结果函数中的如下语句: PrintfE(PID_RED, %d ticks time out!,byMsg1)。 在 byMsg1大于 127时,输出错误的结果。 二、不同数据类型之间的比较操作 在循环终止条件的判断中,不同类型变量的比较操作是容易造成死循环错误的地方,同时也是开发人员容易忽视的地方,值得测试人员多加留意。 下面两个例子是该类错误的两种典型情况: 【例三】 file02文件中某函数中如下代码,可能造成死循环: ...... int i。 WORD *pCheck =(WORD*)p。 WORD wCheckSum=*pCheck。 pCheck++。 for(i=1。 idwLen/2。 i++) { wCheckSum^=(*pCheck)。 pCheck++。 } //binlen had already word alignment return (wCheckSum)。 ...... 该段代码是在 DOS环境下用 BC编译的,由于循环变量 i是 int型( 2个字节),而 dwLen是 DWORD型( 4个字节),如果 dwLen大于 65536,那么该函 数就是死循环了。 上面的例子是不同类型变量之间直接比较操作,还有一种情况是函数的返回值与另一不同类型的变量比较,见下面例子: 【例四】 , while( ftell(fp) Part[3]) {..... } ftell返回 long型,而 Part是 DWORD型,有符号变量和无符号变量的比较,可能造成死循环。 类似的例子还有很多,类型不匹配的问题还有许多种情况,都是代码中的隐患,有时会造成严重的 后果,需要引起足够的重视。 对于该类问题,我们可以利用 PCLINT工具对代码进行细致的检查。 用于控制条件转移的表达式及取值范围是否书写正确 【案例 】 【案例描述】: 在测试主机 MPU板倒换功能时,如果 MPU备份充分,倒换前后对处于激活状态的电路应无影响,即不影响通话。 但近期测试发现,如果两局通过 DT板进行一号对接, MPU备份倒换却发生断话。 具体现象为:如果 DT板的第 1个 PCM系统电路为故障,则 MPU倒换时复位该 DT板,如果 DT板的第 2个 PCM系统电路为故障,则 MPU倒换时复位下一块 DT。 【处理过程】: 据查, MPU倒换时会自动复位处于“故障”态的电路,但由于计算错误(多加了 32),错复位了下一个 PCM系统 32路电路。 【结 论】: 如此严重问题为什么到今天才发现。 因为我们在实验室中一般采用同一单板的 2个 PCM系统自环进行测试,则不会在某单板上有故障和空闲电路共存,自环屏蔽了错误。 【思考与启示】: 自环是在测试环境下常用的一种提高效率的。软件编程规范培训实例与练习-cmmi(编辑修改稿)
阅读剩余 0%
本站所有文章资讯、展示的图片素材等内容均为注册用户上传(部分报媒/平媒内容转载自网络合作媒体),仅供学习参考。
用户通过本站上传、发布的任何内容的知识产权归属用户或原始著作权人所有。如有侵犯您的版权,请联系我们反馈本站将在三个工作日内改正。