




版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
1、2020/6/29,公司常见软件编程低级错误:变量,C语言软件编程规范工作组,前言,这套材料作为编程规范的辅助材料,帮助大家理解编程规范背后的原理。 C和C+语言是我司的主流编程语言,然而C/C+具有很多强大的语言特性,从而导致C/C+非常复杂,使得代码更容易出现BUG、难以阅读和维护。 业界知名的编程规范都对C/C+容易出现问题的语言特性进行管理。例如MISRA(汽车工业软件可靠性联合会)制定的1998版的MISRAC规范指出,一些在C看来可以接受,却存在隐患的地方有127处之多。2004版的MISRAC规范将针对C语言的规则增加到了141条。 对于程序员来说,能工作的代码并不等于“好” 代
2、码。“好”代码的指标很多,包括可读性、可维护性、可移植性和可靠性等。出现网上问题的代码,大多数是不良编程习惯引起的。不遵守编程规范的代码,往往也是最不可靠的代码。 本胶片收集了常见的变量部分案例,给出了相应的纠正措施。对应的编程规范:在首次使用前初始化变量,初始化的地方离使用的地方越近越好;明确全局变量的初始化顺序,避免跨模块的初始化依赖;防止局部变量与全局变量同名;尽量减少没有必要的数据类型默认转换与强制转换。,指针初始值错误,【问题描述】M设备升级到版本后只要是与S设备通过扩展ECC连接的网元都会发生频繁复位 【问题定位】指针m_BoardObject没有申请内存,但赋值为1。后续程序执行
3、时,判断m_BoardObject不等于NULL,于是处理X号板业务。但实际上产品并没有安装X号板,导致系统复位。 【纠正措施】指针m_BoardObject没有使用时,赋初值为NULL。 【举一反三】开发人员处理指针时,通常认为非空指针是合法的,然后就可能调用它。绝对不要写作违背大家习惯的代码。,变量在某些条件下没有初始化,【问题描述】在设备增加对象到最大值时,系统出现段错误 【问题定位】代码如下: VOS_UINT32 ulSlotIndex ; . if (MAX_STACK_CAP m_ulThirdKeyMax) pstSlotStru = (SLOT_STRU *)(m_pucSl
4、otStru + ulSlotIndex * m_ulSlotStruSize); if (VOS_NULL_PTR != pstSlotStru-apObjulThirdKey) return ERROR_PARC_TABLE_OBJ_ALREADY_EXIST; pstSlotStru-apObjulThirdKey = pObj; +m_ulObjNum; +pstSlotStru-ulObjNum; else if (0 = ulThirdKey) /如果不是索引, 同时第三级关键字为0, 那么不用分配槽表项 ulSlotIndex = m_astSubrackulSubrackNo.
5、aulSlotIndexulSlotNo; . pstSlotStru-apObjulSlotIndex = 0; 见红色部分代码,我们可以发现在第一个if中, ulSlotIndex没有被赋值, 还是维持初始值VOS_NULL_LONG。最后用这个去访问数据,结果出现踩内存,结构成员没有初始化(1),【问题描述】位置登记成功后, LM漫游的用户类型变成了区域漫游类型 【问题定位】代码如下: struct TProfileChangedInd unsigned char profile : 1; /1:表示被修改 0:没有修改 unsigned char winService : 1; uns
6、igned char mwnCount : 1; unsigned char reserved : 5; ; (TProfileChangedInd *)sqlProfileChangedInd.arr)-profile = True; 由于只对该结构的profile位进行了赋值,就更新数据库,该结构的其他位的值取了随机值,导致用户的签约类型变化。 【纠正措施】将结构的其他成员赋初始值为0,代码如下: *sqlProfileChangedInd.arr = 0; (TProfileChangedInd *)sqlProfileChangedInd.arr)-profile = True;,结构
7、成员没有初始化(2),【问题描述】HFSSA2到HFAIP2局向接通率凌晨时候偏低 【问题定位】代码如下: ediDspInfooeEntity.m_btEntitySeq.m_dwNMEntityId = oeEntity.m_dwNMEntityId;ediDspInfooeEntity.m_btEntitySeq.m_btValid = 1; ediDspInfooeEntity.m_btEntitySeq.m_btDisplayFormat = oeEntity.m_btDisplayFormat; 发现问题是ediDspInfooeEntity.m_btEntitySeq. m_bt
8、ScaleUnit没有赋值就拿来用,导致ediDspInfooeEntity.m_btEntitySeq. m_btScaleUnit是个随机数,当刚好被随机到“%”时,就产生问题了。 【纠正措施】将结构的成员m_btScaleUnit赋值,代码如下: ediDspInfooeEntity.m_btEntitySeq.m_btScaleUnit = oeEntity.m_btScaleUnit;,数组初始化不正确,【问题描述】在产品测试过程中发现一个随机出现的问题:即主控复位后,与某些单板通信中断。经过反复重现测试,发现了问题重现的一些规律:在每次主控复位之后,插在1、2、3槽位的单板通信都正
9、常,其它槽位均能概率地出现通信中断的现象。 【问题定位】通过检视代码,发现初始化错误: memcpy(m_abBoardWorkMode, g_abBoardWorkMode, WDM_SLOT_NUM); 在负责通信通道注册处理函数中,通过成员变量数组m_abBoardWorkModeWDM_SLOT_NUM来保存各单板工作状态(WDM_SLOT_NUM表示槽位个数,值为14)。单板的工作状态被保存在全局数组g_abBoardWorkModeWDM_SLOT_NUM中,在执行通道注册之前需要把g_abBoardWorkMode赋值给m_abBoardWorkMode。就使用了上面的memcp
10、y()函数。这两个数组都是bool类型的,查询该类型定义为“typedef int bool;”,原来bool被VOS封装为int类型,占4个字节,这样m_abBoardWorkMode和g_abBoardWorkMode两个数组的的大小实际上为14456字节,而memcpy()函数只copy了14个字节,相当于只有前面3个槽位被正确初始化了,4槽位只初始化了前2个字节(bool变量的高字节),514槽位都没有被初始化,这样414槽位的工作状态就是不确定的随机值,所以就随机出现本案例中的现象。 【纠正措施】根据上面的分析,造成主机和单板通信中断的最终原因是数组变量初始化不完全导致的。解决方案有
11、两种:一是仍然使用memcpy()函数,其size参数用sizeof()函数计算,即 memcpy(m_abBoardWorkMode, g_abBoardWorkMode, sizeof(g_abBoardWorkMode); 另一种方法是对数组的每一个元素进行初始化,即 for (DWORD i = 0; i push_back(TmpReqRec); break; . ,临时对象复用但没有初始化(续),在这个方法中,如果碰到EN_FIELD_CS_LIST_END_FALG的tag值即列表结束字段,就认为一个接收方结束地址信息解码结束。但是由于沙特这个问题的特殊性,接收方列表中一个是EM
12、ail地址,一个是手机号码。函数CCSServerCoder:DecodeCSrvReqReceiver中就会遇到两个结束标记EN_FIELD_CS_LIST_END_FALG,所以上面代码会执行两次pCSrvReqReceiver-push_back(TmpReqRec);。但是通过上面的分析,此时EMail地址的归属地字段Server并没有编码发过来,所以第二次pushback的时候会把第一次设置的值给设进去,所以造成了话单中的MMSCID不当的错误。 【纠正措施】下一次使用之前把这个对象的所有成员变量初始化 函数CCSServerCoder:DecodeCSrvResReceiver中的
13、如下代码中添加蓝色字体 case EN_FIELD_CS_LIST_END_FALG: BYTE TempB; _Decode(BYTE,TempB); pCSrvReqReceiver-push_back(TmpReqRec); TmpReqRec.init(); break; 在push_back后初始化临时对象,把所有成员变量的初始化清空。,新增代码时没有初始化老代码结构成员,【问题描述】AIX平台下,配置10000条PPS路由,两个维测台同时操作时,系统core dump 【问题定位】通过检视代码,发现初始化错误: void COMCServer:OnSetPPSRoute_V3R2_
14、1DB(PTRMSG pMsg) MI_SET_PPSROUTE_V3R2_1DB* pInputMsg = (MI_SET_PPSROUTE_V3R2_1DB*)pMsg; MI_SET_PPSROUTE_V3R2_1DB_ACK AckMsg;没有进行初始化 MI_SET_PPSROUTE_V3R2_1DB_ACK* pAckMsg = ,新增代码时没有初始化老代码结构成员(续),惯性的力量导致我们疏忽了维测应答消息的初始化。查看代码,可以发现老代码对维测应答消息的初始化处理非常少,普遍的现象是不初始化,导致对我们新增的控制分支,想到没想就直接加上了。为什么以前都这么做就没出现问题?看一下
15、上面的代码就知道,现存维测消息处理函数的异常分支,除非维测消息有错误,通常情况下是不会进入的,可对于本次新增代码,其发生的条件非常普遍,属于正常的逻辑控制分支,进入的频度就要高很多。习惯了原来的处理方式,没有想过特殊情况特殊处理,问题就出现了。 【纠正措施】给结构的所有成员都初始化,使用错误变量值,【问题描述】一次拨号流程CCS后付费业务交换侧产生话单中计费号码为被叫号码。 【问题定位】查看代码,发现非注册用户拨打电话下发AC时,计费用户标识字段(chargedPartyIdentityIndicator)没有赋值,而平台此时会为该值赋默认值2,即下发AC时chargedPartyIdenti
16、tyIndicator=2,由于该值为2,导致交换在写话单时将计费方认为是被叫计费,而实际此类呼叫应为主叫计费。 【纠正措施】修改非注册用户呼叫流程AC SIB,将计费用户标识字段(chargedPartyIdentityIndicator)赋值为1。,使用错误变量值(变量位数错误),【问题描述】 DHCP offer报文COS字段打上了优先级,导致dhcp模块检测不通过,导致报文被丢掉。 【问题定位】 DHCPR处理用户报文上线报文的时候(问题单中的场景是DHCPR处理DHCPS回复的OFFER报文),从IP层获取报文内容中VLAN时,取了16bit(一个SHORT类型的长度),而我们的VL
17、AN的最大值是12bit,如果所取报文VLAN值前面一位不是0(即报文COS字段打上了非0优先级),那么这个VLAN值就超过 MAX_VLAN_ID ( = 4094 ),导致错误处理。 【纠正措施】 在DHCPR模块处理上线报文时,取12bit的VLAN值解决该问题,即通过位与的方式取报文12bit VLAN值,不在业务模块获取vlan值时取其优先级。,变量值溢出错误,【问题描述】 NNSSA1网元R2C03SPH002版本升级结束之后,通过DSP DSPLNK查询链路状态结果异常。输入不同的链路集查到的结果相同。 【问题定位】扩容引起,取值错误导致溢出。 根据命令码,链路集的取值范围是06
18、5535: DSP DSPLNK 3 = LSX (链路集索引) 065534 但是代码中将该值定义为BYTE类型,如果链路集超过255就会溢出,导致查询出的内容不准确, 【纠正措施】修改函数void CHandleMMLThd:MtCmd_DSP_DSPLNK(CParseResult * pParseResult) 将BYTE byLnkSetIdx = pParseResult-GetDigitVal(LSX); 修改为WORD byLnkSetIdx = pParseResult-GetDigitVal(LSX);,Reset后变量赋值错误,【问题描述】当品牌表设置私密热语号码有地域限
19、制或运营商限制的时候,用户在设置私密热语号码立即生效之后,在不输入私密热语号码的情况下再次进行预约下月关闭,结果报:私密热语号码不能为空!导致用户无法预约关闭。 【问题定位】变量调用Reset函数初始化之后,变量的值并不是空,而后续代码处理认为Reset后变量应该是空值,如果后续判断变量不为空值则认为输入了私密热语号码,引发了后续对私密热语号码变量的存在性校验引起失败 【纠正措施】变量的初始化直接初始化为空,错误使用相似变量,【问题描述】由于ISUP模块在对ISUP消息数进行统计打点时使用了错误的变量,导致ISUP消息数统计结果始终为0,与实际不相符。 。 【问题定位】代码中,在对ISUP消息
20、数进行打点统计时,使用了错误的变量,导致ISUP消息计数器没有被打点上,造成ISUP接收消息数话统值恒为0。 应该使用: MTP_MS_D_SL_ISUP_MSUS_RECEIVE 错误的使用了: MTP_MS_D_SL_ISUP_OCTETS_RECEIVE 【纠正措施】修改对ISUP消息数进行打点时,使用正确的变量,重复定义成员变量为一个局部变量,【问题描述】在类的初始化函数中对一个成员变量进行初始化,但后续访问却失败。 【问题定位】问题类代码的声明如下: CSomeClass TSomeType *m_pSomeMember; / 示例成员变量 Public: CSomeClass();
21、 / 构造函数,用于初始化成员变量 void AccessSomeMember(); / 访问成员变量 问题类代码的实现如下: CSomeClass:CSomeClass() TSomeType *m_pSomeMember = new TSomeType; / 此处申请成员变量,运行正常 int nTempValue = m_pSomeMember-m_nSomeMember; / 此处运行也正常,值也正确 void CSomeClass:AccessSomeMember() int nValue = m_pSomeMember-m_nSomeMember; / 此处运行异常,产生错误 ,重
22、复定义成员变量为一个局部变量(续),出错的原因在于构造函数中(上述红色示出的代码)申请的m_pSomeMember是局部变量,仅在构造函数的范围内有效,而CSomeClass:m_pSomeMember成员并没有被申请初始化,故在后续的访问中出错误。(此错误是编程人员在编码过程中,将类声明中的TSomeType *m_pSomeMember直接复制粘贴到构造函数中,从而导致此错误) 【纠正措施】在构造函数中重复定义了和构造函数重名的局部变量,造成对成员变量的赋初值没有起作用,才会在后续的访问中失败。对该例子中的问题的改进方法如下:将构造函数中的TSomeType *m_pSomeMember前
23、面的TSomeType *去掉,再访问该变量时可以正常的访问了。 【举一反三】局部变量的命名要尽量避免与成员变量、全局变量重名,这样一方面对代码的维护带来了很大的影响,代码的可读性也会大大降低;另一方面代码的编写者也很容易造成错误。,全局变量初始化顺序错误(1),【问题描述】双归属倒换后位置更新失败 【问题定位】函数依赖于全局变量,函数调用在全局变量正确赋值之前。 SCCP_ReflashGTGroupData(); . gucSccpAdaptOtherServerActived = NULL_BYTE; for (i = 1; i MAX_ASSIST_SERVER_NUM; i+ ) i
24、f (DEV_DH_ASSIST_ACTIVE = DEV_DHGetServerAssistState(i) gucSccpAdaptOtherServerActived = i; break; 【纠正措施】将SNC相关的处理放到赋值后面处理。 gucSccpAdaptOtherServerActived = NULL_BYTE; for (i = 1; i MAX_ASSIST_SERVER_NUM; i+ ) if (DEV_DH_ASSIST_ACTIVE = DEV_DHGetServerAssistState(i) gucSccpAdaptOtherServerActived =
25、i; break; SCCP_ReflashGTGroupData();,全局变量初始化顺序错误(2),【问题描述】UAP2105某R版本发布后,希腊VDF反馈AP上电后,在APM上立即查看GSM邻区为空,一段时间过后,GSM邻区才概率性出现。 【问题定位】先介绍一个全局变量小区建立模式的定义: 它在Nbmglobal.c中是这样定义的: NBM_CELL_STRU * gpaCell = VOS_NULL_PTR; 其中主角成员ucCfgMode在结构体位置如下:gpaCell0.CellInfo.ucCfgMode; ucCfgMode取值范围为DBAPI_AUTO_CFG(1)、DBAP
26、I_MANUAL_CFG(2)。 这个变量用来记录AP小区建立模式,包括自动网规模式还是手动网规模式;当我们配置自动模式的时候,AP上电将按照自动网规模式进行小区建立。 GSM邻区自动搜索时,根据该小区配置模式gpaCell0.CellInfo.ucCfgMode,把GSM邻区保存起来。如果小区是自动模式,那么GSM自动搜索的邻区将被保存。 实验室测试发现,AP自动网规模式起来后,在APM上立即查看GSM自动搜索的邻区为空;但从串口打印分析,GSM接收机启动、搜索流程均正常、邻区也搜索也成功,什么原因导致GSM邻区丢失?继续测试观察,又发现:经过一段时间当GSM邻区搜索再次更新时,在APM上查看GSM邻区又存在,为什么在系统启动时第一次GSM搜索邻区不能保存,第二次更新后就能保存下来?,全局变量初始化顺序错误(2)(续一),存在,为什么在系统启动时第一次GSM搜索邻区不能保存,第二次更新后就能保存下来? 排查代码,发现保存GSM邻区代码很简单: if (DBAPI_AUTO_CFG = gpaCell0.CellInfo.ucCfgMode)(如果自动网规模式,邻区写入DB) ulRslt = DBAPI_SetInterRatNCellInfo(pInterRatNCellList); if (D
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 福建事业单位考试社会心理特征试题及答案
- 花卉工作面试题及答案
- 毛概第11章试题及答案
- 拓展花艺师视野的策略的试题及答案
- 农艺师考试团队合作能力提升试题及答案
- 中招考试圆的试题及答案
- 2024年福建事业单位考试社区服务试题及答案
- 2024年福建事业单位考试全新视角试题及答案
- 机械性能考试题及答案
- 土壤肥料学试题库及答案
- 少喝饮料安全教育
- 儿童心理健康与家庭教育关系
- 2025届山东省临沂市高三下学期一模考试英语试卷(含解析)
- 2025年河南水利与环境职业学院单招职业倾向性测试题库学生专用
- 2025年人体捐献协议
- 《法律职业伦理》课件-第二讲 法官职业伦理
- 《专业咖啡制作技术》课件
- 印刷行业售后服务质量保障措施
- 《急性阑尾炎幻灯》课件
- 员工黄赌毒法制培训
- 舞蹈工作室前台接待聘用合同
评论
0/150
提交评论