WORD WHdlcDIc WORD wPeerHdlcDIci WORD wPeerOld AtmPort s SFrPppIntIWFData DWORD SaveFrNetIntI WFData (dWOrD'pdw WritePoint bYte bSlotId. bPeerSlotID dword dw CCID. dwPeerCCID WORD wHdIcPort, wAtmPort, wIci, wPeerlci, w PeerHdIcPort WORD wCount DWORD Save FrNetExtI WFData( DWORD*pdw WritePoint bYte bSlotID dWord dwccid. dwPeerCCID WORD wHdIcPort wAtmPort. wIci WORD WCount unSev Data FrNet ExtI[wCount]. bSlotID =bSlotID unSevData. FrNetExtIwflw Count]. wHdIcPort = wHdIcPort unSev Data FrNet ExtI WFlwCount] wHdlclci gFrPVCEP[bSlotiD[ gFrPVCC[bSlotIDdwCCID) dwLoPVCEP ].dw DLCI; unSevData. FrNetExtIWFlwCount wOldAtmPort =wAtmPort unSevData. FrNetExtI WFlwCount] wAtmDlci gFrPVCEP[ bSlotID[ gFrPVCC[bSlotIDIIdwCCiD]dwHiPVCEP ]dwDLCI; un SevData FrNet ExtI WFlwCount] dwMap Mode
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[ CCiD]. dwMapMode DWORD RestoreFrNet ExtIWFData( WORD wSlotID, BYTE pRead Point WORD wCount wTotalNetIWF BYTE bSlotID, bHdIcDIciType, bAtmDIciType; WORD wOld AtmPort. wAtmDIci wHdlcPort. wHdlcDIci dWord dw MapMode, dwCiR, dwBe; dord dwCcid. dwResult. dw AtmPort wTotalNetI WF=g MuxData SevDataSize w ExtI WFNum DWORD RestoreFrHdIcIntI WFData( WORD wSlotID, BYTE*pRead Point WORD WCount wTotalHdIcIWF dword dwCCID. dwPeerCCID dwAtmPort dwPeer AtmPort dWord dwResult bYte bSlotId. bPeerSlotID WORD wHdIcPort, wOld AtmPort, wCIR; WORD wPeerHdIcPort wPeerOld AtmPort 其中涉及DLCI值的变量都为WORD(即无符号短整型)类型,在程序 的处理时,出现WORD和WORD(无符号长整型)类型在一句中同时存在的情
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值在不同类型时的取值范围不同, 前三种类型的取值范围为l6~991,第四种取值范围为2048~126975,第五种取值 范围为131072~4194303,所以当采用前三种DLCI类型时,采用WORD类型最大 值为65535,已经完全够用了;而对于第四种类型时,其取值在超过65535时,获 取DLCI值的函数 GetfrDIci()采用 DWORD类型,而负责保存和恢复的两个函 数 SaveFrNetExtIwFData()和 Restore frNet extIwfdata(),都把DLCI的值当 作WORD类型进行处理,因此导致DLCI取值越界,于是程序把原本为长整型的 DLCI强制转换成整型,从而导致DLCI值在恢复时,比原数据小65536。而在程 序运行过程中,这些数据保存在DRAM中,程序运行直接从DRAM中获取数据, 程序不会出错;当FRI板复位或插拔后,需要从 FLASH中读取数据,此时恢复函 数的错误就表现出来。 另一个问题是为什么23/4类型的DLCI数据不能恢复?这是由于对于23/4 类型的PⅤC,其DLCI的取值范围为:131072-4194303,而程序强制转换并恢复 的数据最大只能是65535,所以这条PⅤC不能恢复。 至此,DLCI数据恢复出错的原因完全找到,解决的方法是将DLCI的类 型改为 DWORD类型。从这个案例可以看出,在程序开发中一个很低级的错误, 将在实际工作中造成很严重的后果 5、正确使用逻辑与&&、屏蔽&操作符 【案例151】 【案例描述】:由于C语言中位与比求模效率高,因而系统设计时,对于模128 的地方都改为与127,系统定义的宏为# define mod128127和# define w mod 127(定义的宏的名字易引起误解),但实际程序中还是采取求模,从而引起发送 窗口欲重发的和实际重发的不一致,最终导致链路复位此类严重问题,曾在定位 此问题时花了不少时间。 【处理过程】:处理过程如下 #define MOD128 27∥队列长128,当队头到128时,上其返回。 #define W MOD 127∥发送窗口队列,意义同上
况,至此可以判断问题出在这里。由于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 //发送窗口队列,意义同上
在函数L2TOL10中,有如下语句 linkstate_ptr->Send Win. head=(head 1)%W MOD 这里当head=126时, Send win head=0,这将造成发送窗口指针和队列窗口指针 错位,造成链路复位 另外,在重发函数 void INVOKE RETRANSMISSION( US logic link,USnr)中, 有如下语句 retran num=(Link State[ logic link]. VS MOD128 -( UC)n r)% MODI2 w head -(Link State[ logic link). Send win. head W MOD retran num)%WMOD 第一个语句求欲重发的消息包个数,第二个语句求重发的起始位置,当Ⅴs小于 nr时,将造成实际重发数小于欲重发数,同时造成实际起始重发位置和欲重发 起始位置错开,从而引起链路复位。上面三个语句应该做如下改动: linkstate ptr->Send Win. head=(head 1)&W mOd retran num=LinkState logic link]. VS+ MOD128 +1-(UC)n r)& MOD 128 w head=( LinkState[logic link]. Send win. head + W MOD+ 1 retran num)& WmOd 【结论】:由于链路通信对系统效率要求很高,算法采用效率最高的,但位与 (&)和求模(%)这小小的区别,造成的竟是链路复位这种严重的错误。 【思考与启示】:对这类问题,大家在阅读代码或代码审查时一定要注意,仔细 一点往往能发现问题,但在测试中来定位这种问题,花费的时间往往更长 6、注意数据类型的匹配 案例16.1】 【案例描述】 下面通过测试中的一个例子来说明这个问题:命令DSPN7C是用来显示NO7
在函数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、注意数据类型的匹配 【案例1.6.1】 【案例描述】 下面通过测试中的一个例子来说明这个问题:命令DSP N7C是用来显示NO7
电路状态的,其参数设备类型DID支持TUP和ISUP,参数信道号BSN支持多值输 入(最多支持32路査询),正常情况下该命令没有问题。但试了非正常情况下, 问题就出来了。 1、首先试BSN参数越界情况,即参数BSN超过32路查询,选了几个数据段, 问题就出来了。对于0&&300和0&&256,该命令返回结果不一致,对前者认为 参数越界,对后者返回执行成功。 2、对于参数DID,选定一种设备类型(TUP或ISUP),让参数BSN所包含的 32路电路跨越TUP和ISUP,两次结果是不一致的 【处理过程】 反馈到开发人员那里,第一个问题是BAM的问题,第二个问题是SM的问题。 【结论】 、为数据超出范围溢出造成,int值赋值给BYTE,造成数据丢失 2、问题的产生是因为查询的第一个信道是TUP电路,但是却按ISUP电路查 询。ISUP的维护处理函数判断第一个信道不是ISUP信道,认为整个的PCM不是 ISUP类型的PCM,返回全部的电路状态为未安装。消息处理不合理。TUP也会 产生如此错误。 【思考与启示】 我们的MML命令并不是无懈可击的,许多表面上的小问题,往往隐藏着代 码的缺陷和错误 【案例16.2】 【正 文】 当我们使用 PC-LINT检查代码时,会发现大量的数据类型不匹配的告警, 大部分情况下,这种代码上存在的问题并不会引起程序功能实现上的错误,但有 些情况下,也许会产生严重的问题: 不同数据类型变量之间赋值引起的问题,实际上,该类问题也可以 分为几种情况:
电路状态的,其参数设备类型DID支持TUP和ISUP,参数信道号BSN支持多值输 入(最多支持32路查询),正常情况下该命令没有问题。但试了非正常情况下, 问题就出来了。 1、首先试BSN参数越界情况,即参数BSN超过32路查询,选了几个数据段, 问题就出来了。对于0&&300和0&&256,该命令返回结果不一致,对前者认为 参数越界,对后者返回执行成功。 2、对于参数DID,选定一种设备类型(TUP或ISUP),让参数BSN所包含的 32路电路跨越TUP和ISUP,两次结果是不一致的。 【处理过程】 反馈到开发人员那里,第一个问题是BAM的问题,第二个问题是SM的问题。 【结 论】 1、为数据超出范围溢出造成,int值赋值给BYTE,造成数据丢失。 2、问题的产生是因为查询的第一个信道是TUP电路,但是却按ISUP电路查 询。ISUP的维护处理函数判断第一个信道不是ISUP信道,认为整个的PCM不是 ISUP类型的PCM,返回全部的电路状态为未安装。消息处理不合理。TUP也会 产生如此错误。 【思考与启示】 我们的MML命令并不是无懈可击的,许多表面上的小问题,往往隐藏着代 码的缺陷和错误。 【案例1.6.2】 【正 文】 当我们使用PC-LINT检查代码时,会发现大量的数据类型不匹配的告警, 大部分情况下,这种代码上存在的问题并不会引起程序功能实现上的错误,但有 些情况下,也许会产生严重的问题: 一、不同数据类型变量之间赋值引起的问题,实际上,该类问题也可以 分为几种情况: