资源描述
软件编程规范培训实例与练习
问题分类
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.cDeviceDslMsgProc()函数中解决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和991PVC对的恢复,而DLCI=126975PVC恢复数据错误为61439,而DLCI=1234567PVC完全没有恢复。
对于17/4类型,DLCI=126975PVC在恢复时变成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和991PVC对的恢复,而DLCI=126975PVC恢复数据错误为61439,而DLCI=1234567PVC完全没有恢复。
对于17/4类型,DLCI=126975PVC在恢复时变成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、注意数据类型匹配
【案例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问题。
【结 论】
1、为数据超过范畴溢出导致,int值赋值给BYTE,导致数据丢失。
2、问题产生是由于查询第一种信道是TUP电路,但是却按ISUP电路查询。ISUP维护解决函数判断第一种信道不是ISUP信道,以为整个PCM不是ISUP类型PCM,返回所有电路状态为未安装。消息解决不合理。TUP也会产生如此错误。
【思考与启示】
咱们MML命令并不是无懈可击,许多表面上小问题,往往隐藏着代码缺陷和错误。
【案例1.6.2】
【正 文】
当咱们使用PC-LINT检查代码时,会发现大量数据类型不匹配告警,大某些状况下,这种代码上存在问题并不会引起程序功能实现上错误,但有些状况下,也许会产生严重问题:
一、不同数据类型变量之间赋值引起问题,事实上,该类问题也可以分为几种状况:
1、直接赋值,例如,把一种WORD型变量赋给一种INT型变量,如果WORD型变量不不大
展开阅读全文