收藏 分销(赏)

软件编程规范培训实例与练习样本.doc

上传人:二*** 文档编号:4738604 上传时间:2024-10-11 格式:DOC 页数:78 大小:296.54KB
下载 相关 举报
软件编程规范培训实例与练习样本.doc_第1页
第1页 / 共78页
亲,该文档总共78页,到这儿已超出免费预览范围,如果喜欢就下载吧!
资源描述

1、软件编程规范培训实例与练习 问题分类1 逻辑类问题(A类)指设计、编码中浮现计算对的性和一致性、程序逻辑控制等方面浮现问题,在系统中起核心作用,将导致软件死机、功能正常实现等严重问题; 接口类问题(B类)指设计、编码中浮现函数和环境、其她函数、全局/局部变量或数据变量之间数据/控制传播不匹配问题,在系统中起重要作用,将导致模块间配合失效等严重问题; 维护类问题(C类)指设计、编码中浮现对软件系统维护以便限度导致影响问题,在系统中不起核心作用,但对系统后期维护导致不便或导致维护费用上升; 可测试性问题(D类)指设计、编码中因考虑不周而导致后期系统可测试性差问题。 惩罚办法 问题发生率: P=D/

2、S D=DA+0.5DB+0.25DC 其中: P 问题发生率 D 1个季度内错误总数 DA 1个季度内A类错误总数 DB 1个季度内B类错误总数 DC 1个季度内C类错误总数 S 1个季度内收到问题报告单总数 1)当D3时,如果P3,将进行警告解决,并予以公示; 2)当D5时,如果P5,将进行罚款解决,并予以公示。目 录一、逻辑类代码问题第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、变量类

3、型定义错误第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

4、.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、注释量至少占代码总量2

5、0第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语言中最大特色就是指针。指针使用品有很强技巧性和灵活性,但同步也带来了很大

6、危险性。在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). .其中红色某些巧妙运用指向指针指针为指针p

7、uc_card_config_tab赋值,而在兰色某些使用该指针。但在Get_Config_Table函数中有也许失败返回而不给该指针赋值。因而,后来使用也许是一种非法指针。指针使用是非常灵活,同步也存在危险性,必要小心使用。指针使用危险性举世共知。在新编程思想中,指针基本上被禁止使用(JAVA中就是这样),至少也是被限制使用。而在咱们互换机程序中大量使用指针,并且有增无减。2、防止指针/数组操作越界【案例1.2.1】 在香港项目测试中,发现ISDN话机拨新业务号码时,若一位一位拨至18位,不会有问题。但若先拨完号码再成组发送,会导致MPU死机。 解决过程: 查错过程很简朴,按呼喊解决过程检查

8、代码,发现某一处判断有误,本应为不大于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群向

9、为入中继,对这四个群分别进行计费设立,对出入中继都计费。电话60640001拨打两次,使四个群均有机会被计费,取话单后浏览话单发现对11群计费计次表话单出中继群号不对的,其他群计次表中出中继群号正常。解决过程:与开发人员在测试组环境多次重复以上环节,发现11群计次表话单有时正常,有时其出中继群号就为一种随机值,发生异常频率比较高。为什么其他群话单正常,唯独11群不正常呢?11群是四个群中最小群,其中继计次表位于缓冲区首位,打完电话后查询内存发现出中继群号在内存中是对的,取完话单后再查就不对的了。结 论:话单池一种备份指针Pool_head_1和中继计次表头指针重叠,影响到第一种中继计次表计费。

10、思考与启示:随机值背后往往隐藏着指针问题,两块内存缓冲区交界处比较容易浮现问题,在编程时是应当注意地方。【案例1.2.3】【正 文】 在接入网产品A测试中,在内存数据库正常状况下各种数据库方面操作都是正常。为了进行数据库异常测试,于是将数据库内容人为地破坏了。发当前对数据库进行比较操作时,浮现程序跑死了现象。通过跟踪调试发现问题出当前如下一段代码中: 1for(i=0;idbf_count;i+)23 pDBFat = (_NM_DBFAT_STRUC *)(NVDB_BASE + DBFAT_OFFSET + i*DBFAT_LEN);4if(fat_check(pDBFat) != 0)

11、56 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(总线出错),由此可以阐明浮现了内存操作异常。通过跟踪变量值发现循

12、环变量i阀值pSysHead-dbf_count数值为0xFFFFFFFF,该值是从被破坏内存数据库中获取,正常状况下该值不大于127。而pDBFat是数据库起始地址,如果pSysHead-dbf_count值异常过大,将导致pDBFat值超过最大内存地址值,随后进行内存操作将导致内存操作越界错误,因而在测试过程中数据库破坏后就浮现了主机死机现象。上面问题解决起来很容易,只需在第一行代码中增长一种判断条件即可,如下:for(i=0;idbf_coun & i bySpcState )语句时,主机复位。但是该语句似乎并无不当。再分析整个函数,pSpcCB在函数前某些已经被赋值,pSpcCB =

13、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_STAT

14、E_OK = pSpcCB-bySpcState )。修改后,问题不再重现。通过度析可以发现,编译环境是有很大容许空间,若主机没有做充分保护,很也许会有极严重随后故障浮现。因此编程时一定要考虑各种也许状况;而测试中遇到此类死机问题,则要耐心定位到详细是执行哪句代码时浮现,再进行分析。由于问题很隐蔽,直接分析海同样代码是很难发现。4、变量类型定义错误【案例1.4.1】【正 文】 在FRI板上建几条FRPVC,其DLCI类型分别为:10Bit/2bytes、10bit/3bytes、16bit/3bytes、17bit/4bytes、23bit/4bytes。相应DLCI值为:16、234、991

15、、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) 先建P

16、VC,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;charszArg80;1charszLine80;IDLowPVCEP; DWO

17、RDdwDlciVal52 = 16,1007,16,1007,1024,64511, 2048,129023,131072,4194303 ; typedef struct tagFrPppIntIWFWORDwHdlcPort;WORDwHdlcDlci; WORDwPeerHdlcDlci; WORDwPeerOldAtmPort;SFrPppIntIWFData;DWORD SaveFrNetIntIWFData ( DWORD *pdwWritePoint )BYTEbSlotID,bPeerSlotID;DWORDdwCCID,dwPeerCCID;WORDwHdlcPort,wA

18、tmPort,wIci,wPeerIci,wPeerHdlcPort ;WORDwCount; DWORD SaveFrNetExtIWFData ( DWORD *pdwWritePoint )BYTEbSlotID;DWORDdwCCID,dwPeerCCID;WORDwHdlcPort,wAtmPort,wIci ;WORDwCount;unSevData.FrNetExtIWFwCount.bSlotID= bSlotID;unSevData.FrNetExtIWFwCount.wHdlcPort= wHdlcPort;unSevData.FrNetExtIWFwCount.wHdlc

19、Dlci= gFrPVCEPbSlotID gFrPVCCbSlotIDdwCCID.dwLoPVCEP .dwDLCI;unSevData.FrNetExtIWFwCount.wOldAtmPort= wAtmPort;unSevData.FrNetExtIWFwCount.wAtmDlci= gFrPVCEP bSlotID gFrPVCCbSlotIDdwCCID.dwHiPVCEP .dwDLCI;unSevData.FrNetExtIWFwCount.dwMapMode = gFrPVCCbSlotIDdwCCID.dwMapMode; DWORD RestoreFrNetExtIW

20、FData ( WORD wSlotID,BYTE *pReadPoint )WORDwCount,wTotalNetIWF;BYTEbSlotID,bHdlcDlciType,bAtmDlciType;WORDwOldAtmPort,wAtmDlci,wHdlcPort,wHdlcDlci; DWORDdwMapMode,dwCIR,dwBe;DWORDdwCCID,dwResult,dwAtmPort;wTotalNetIWF = g_MuxData.SevDataSize.wFrNetExtIWFNum;DWORD RestoreFrHdlcIntIWFData ( WORD wSlot

21、ID,BYTE *pReadPoint )WORDwCount,wTotalHdlcIWF;DWORDdwCCID,dwPeerCCID,dwAtmPort,dwPeerAtmPort;DWORDdwResult;BYTEbSlotID,bPeerSlotID;WORDwHdlcPort,wOldAtmPort,wCIR;WORDwPeerHdlcPort,wPeerOldAtmPort; 其中涉及DLCI值变量都为WORD(即无符号短整型)类型,在程序解决时,浮现WORD和DWORD(无符号长整型)类型在一句中同步存在状况,至此可以判断问题出在这里。由于DLCI值在不同类型时取值范畴不同,前

22、三种类型取值范畴为16991,第四种取值范畴为2048126975,第五种取值范畴为1310724194303,因此当采用前三种DLCI类型时,采用WORD类型最大值为65535,已经完全够用了;而对于第四种类型时,其取值在超过65535时,获取DLCI值函数_GetFrDlci()采用DWORD类型,而负责保存和恢复两个函数SaveFrNetExtIWFData()和RestoreFrNetExtIWFData(),都把DLCI值当作WORD类型进行解决,因而导致DLCI取值越界,于是程序把原本为长整型DLCI强制转换成整型,从而导致DLCI值在恢复时,比原数据小65536。而在程序运营过程

23、中,这些数据保存在DRAM中,程序运营直接从DRAM中获取数据,程序不会出错;当FRI板复位或插拔后,需要从FLASH中读取数据,此时恢复函数错误就体现出来。 另一种问题是为什么23/4类型DLCI数据不能恢复?这是由于对于23/4类型PVC,其DLCI取值范畴为:1310724194303,而程序强制转换并恢复数据最大只能是65535,因此这条PVC不能恢复。 至此,DLCI数据恢复出错因素完全找到,解决办法是将DLCI类型改为DWORD类型。从这个案例可以看出,在程序开发中一种很低档错误,将在实际工作中导致很严重后果。【案例1.4.2】【正 文】 在FRI板上建几条FRPVC,其DLCI类

24、型分别为: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,也就是说在数据恢复或保存时把原

25、数据第一种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 dwPortTyp

26、e,DWORD dwSlotID,DWORD dwPortID) DWORD tempDlci;charszArg80;charszLine80;IDLowPVCEP; DWORDdwDlciVal52 = 16,1007,16,1007,1024,64511, 2048,129023,131072,4194303 ; typedef struct tagFrPppIntIWFWORDwHdlcPort;WORDwHdlcDlci; WORDwPeerHdlcDlci; WORDwPeerOldAtmPort;SFrPppIntIWFData;DWORD SaveFrNetIntIWFData

27、 ( DWORD *pdwWritePoint )BYTEbSlotID,bPeerSlotID;DWORDdwCCID,dwPeerCCID;WORDwHdlcPort,wAtmPort,wIci,wPeerIci,wPeerHdlcPort ;WORDwCount; DWORD SaveFrNetExtIWFData ( DWORD *pdwWritePoint )BYTEbSlotID;DWORDdwCCID,dwPeerCCID;WORDwHdlcPort,wAtmPort,wIci ;WORDwCount;unSevData.FrNetExtIWFwCount.bSlotID= bS

28、lotID;unSevData.FrNetExtIWFwCount.wHdlcPort= wHdlcPort;unSevData.FrNetExtIWFwCount.wHdlcDlci= gFrPVCEPbSlotID gFrPVCCbSlotIDdwCCID.dwLoPVCEP .dwDLCI;unSevData.FrNetExtIWFwCount.wOldAtmPort= wAtmPort;unSevData.FrNetExtIWFwCount.wAtmDlci= gFrPVCEP bSlotID gFrPVCCbSlotIDdwCCID.dwHiPVCEP .dwDLCI;unSevDa

29、ta.FrNetExtIWFwCount.dwMapMode = gFrPVCCbSlotIDdwCCID.dwMapMode; DWORD RestoreFrNetExtIWFData ( WORD wSlotID,BYTE *pReadPoint )WORDwCount,wTotalNetIWF;BYTEbSlotID,bHdlcDlciType,bAtmDlciType;WORDwOldAtmPort,wAtmDlci,wHdlcPort,wHdlcDlci; DWORDdwMapMode,dwCIR,dwBe;DWORDdwCCID,dwResult,dwAtmPort;wTotalN

30、etIWF = g_MuxData.SevDataSize.wFrNetExtIWFNum;DWORD RestoreFrHdlcIntIWFData ( WORD wSlotID,BYTE *pReadPoint )WORDwCount,wTotalHdlcIWF;DWORDdwCCID,dwPeerCCID,dwAtmPort,dwPeerAtmPort;DWORDdwResult;BYTEbSlotID,bPeerSlotID;WORDwHdlcPort,wOldAtmPort,wCIR;WORDwPeerHdlcPort,wPeerOldAtmPort; 其中涉及DLCI值变量都为WO

31、RD(即无符号短整型)类型,在程序解决时,浮现WORD和DWORD(无符号长整型)类型在一句中同步存在状况,至此可以判断问题出在这里。由于DLCI值在不同类型时取值范畴不同,前三种类型取值范畴为16991,第四种取值范畴为2048126975,第五种取值范畴为1310724194303,因此当采用前三种DLCI类型时,采用WORD类型最大值为65535,已经完全够用了;而对于第四种类型时,其取值在超过65535时,获取DLCI值函数_GetFrDlci()采用DWORD类型,而负责保存和恢复两个函数SaveFrNetExtIWFData()和RestoreFrNetExtIWFData(),都

32、把DLCI值当作WORD类型进行解决,因而导致DLCI取值越界,于是程序把原本为长整型DLCI强制转换成整型,从而导致DLCI值在恢复时,比原数据小65536。而在程序运营过程中,这些数据保存在DRAM中,程序运营直接从DRAM中获取数据,程序不会出错;当FRI板复位或插拔后,需要从FLASH中读取数据,此时恢复函数错误就体现出来。 另一种问题是为什么23/4类型DLCI数据不能恢复?这是由于对于23/4类型PVC,其DLCI取值范畴为:1310724194303,而程序强制转换并恢复数据最大只能是65535,因此这条PVC不能恢复。 至此,DLCI数据恢复出错因素完全找到,解决办法是将DLC

33、I类型改为DWORD类型。从这个案例可以看出,在程序开发中一种很低档错误,将在实际工作中导致很严重后果。5、对的使用逻辑与&、屏蔽&操作符【案例1.5.1】【案例描述】:由于C语言中位与比求模效率高,因而系统设计时,对于模128地方都改为与127,系统定义宏为#define MOD128 127和#define W_MOD 127(定义宏名字易引起误解),但实际程序中还是采用求模,从而引起发送窗口欲重发和实际重发不一致,最后导致链路复位此类严重问题,曾在定位此问题时花了不少时间。【解决过程】:解决过程如下:#define MOD128 127 /队列长128,当队头到128时,上其返回。#de

34、fine 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 = (LinkStatelogic_link.Vs + MOD128 - (_UC)n_r) % MOD128 ; w_head =

35、 (LinkStatelogic_link.SendWin.head + W_MOD - retran_num) % W_MOD ;第一种语句求欲重发消息包个数,第二个语句求重发起始位置,当Vs不大于n_r时,将导致实际重发数不大于欲重发数,同步导致实际起始重发位置和欲重发起始位置错开,从而引起链路复位。上面三个语句应当做如下改动: linkstate_ptr-SendWin.head = (head + 1) & W_MOD ; retran_num = (LinkStatelogic_link.Vs + MOD128 + 1 - (_UC)n_r) & MOD128 ; w_head =

36、(LinkStatelogic_link.SendWin.head + W_MOD + 1 - retran_num) & W_MOD ;【结 论】:由于链路通信对系统效率规定很高,算法采用效率最高,但位与(&)和求模(%)这小社区别,导致竟是链路复位这种严重错误。【思考与启示】:对此类问题,人们在阅读代码或代码审查时一定要注意,仔细一点往往能发现问题,但在测试中来定位这种问题,耗费时间往往更长。6、注意数据类型匹配【案例1.6.1】【案例描述】下面通过测试中一种例子来阐明这个问题:命令DSP N7C是用来显示NO7电路状态,其参数设备类型DID支持TUP和ISUP,参数信道号BSN支持多值输

37、入(最多支持32路查询),正常状况下该命令没有问题。但试了非正常状况下,问题就出来了。1、一方面试BSN参数越界状况,即参数BSN超过32路查询,选了几种数据段,问题就出来了。对于0&300和0&256,该命令返回成果不一致,对前者以为参数越界,对后者返回执行成功。2、对于参数DID,选定一种设备类型(TUP或ISUP),让参数BSN所包括32路电路跨越TUP和ISUP,两次成果是不一致。【解决过程】反馈到开发人员那里,第一种问题是BAM问题,第二个问题是SM问题。【结 论】1、为数据超过范畴溢出导致,int值赋值给BYTE,导致数据丢失。2、问题产生是由于查询第一种信道是TUP电路,但是却按

38、ISUP电路查询。ISUP维护解决函数判断第一种信道不是ISUP信道,以为整个PCM不是ISUP类型PCM,返回所有电路状态为未安装。消息解决不合理。TUP也会产生如此错误。【思考与启示】咱们MML命令并不是无懈可击,许多表面上小问题,往往隐藏着代码缺陷和错误。【案例1.6.2】【正 文】当咱们使用PC-LINT检查代码时,会发现大量数据类型不匹配告警,大某些状况下,这种代码上存在问题并不会引起程序功能实现上错误,但有些状况下,也许会产生严重问题: 一、不同数据类型变量之间赋值引起问题,事实上,该类问题也可以分为几种状况:1、直接赋值,例如,把一种WORD型变量赋给一种INT型变量,如果WORD型变量不不大

展开阅读全文
相似文档                                   自信AI助手自信AI助手
猜你喜欢                                   自信AI导航自信AI导航
搜索标签

当前位置:首页 > 包罗万象 > 大杂烩

移动网页_全站_页脚广告1

关于我们      便捷服务       自信AI       AI导航        获赠5币

©2010-2024 宁波自信网络信息技术有限公司  版权所有

客服电话:4008-655-100  投诉/维权电话:4009-655-100

gongan.png浙公网安备33021202000488号   

icp.png浙ICP备2021020529号-1  |  浙B2-20240490  

关注我们 :gzh.png    weibo.png    LOFTER.png 

客服