当前位置:高等教育资讯网  >  中国高校课件下载中心  >  大学文库  >  浏览文档

华为:《编程规范与案例》软件编程规范培训实例与练习

资源类别:文库,文档格式:DOC,文档页数:70,文件大小:326.5KB,团购合买
1 逻辑类问题(A类)-指设计、编码中出现的计算正确性和一致性、程 序逻辑控制等方面出现的问题,在系统中起关键作用,将导致软件死机、功能正 常实现等严重问题; 接口类问题(B类)-指设计、编码中出现的函数和环境、其他函数、全 局/局部变量或数据变量之间的数据/控制传输不匹配的问题,在系统中起重要作 用,将导致模块间配合失效等严重问题;
点击下载完整版文档(DOC)

软件编程规范培训实例与练习 问题分类 逻辑类问题(A类)一指设计、编码中出现的计算正确性和一致性、程 序逻辑控制等方面出现的问题,在系统中起关键作用,将导致软件死机、功能正 常实现等严重问题 接口类问题(B类)一指设计、编码中出现的函数和环境、其他函数、全 局/局部变量或数据变量之间的数据/控制传输不匹配的问题,在系统中起重要作 用,将导致模块间配合失效等严重问题 维护类问题(C类)一指设计、编码中出现的对软件系统的维护方便程度 造成影响的问题,在系统中不起关键作用,但对系统后期维护造成不便或导致维 护费用上升; 可测试性问题(D类)一指设计、编码中因考虑不周而导致后期系统可测 试性差的问题。 处罚办法 问题发生率: P=D/S D=D4+0.5D+0.25D 其中: 问题发生率 D-1个季度内错误总数 D4-1个季度内A类错误总数 D-1个季度内B类错误总数 Dc-1个季度内C类错误总数 S-1个季度内收到问题报告单总数 1)当D≥3时,如果P≥3%,将进行警告处理,并予以公告 2)当D≥5时,如果P≥5%,将进行罚款处理,并予以公告

软件编程规范培训实例与练习  问题分类 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页 逻辑类代码问题 变量指针在使用前就必须初始化 第5页 【案例111】 第5页 2、防止指针数组操作越界 第5页 【案例121】 第5页 【案例122】 第6页 案例123】 第7页 【案例124】 第8页 3、避免指针的非法引用 第9页 案例13.1】 第9页 4、变量类型定义错误 第10页 【案例141】 第10页 5、正确使用逻辑与&&、屏蔽&操作符 第17页 【案例151】 第17页 6、注意数据类型的匹配 第18页 【案例161】 第18页 【案例16.2】 第18页 7、用于控制条件转移的表达式及取值范围是否书写正确 第20页 【案例171】 第20页 【案例172】 第21页 【案例173】 第22页 8、条件分支处理是否有遗漏 第24页 案例181】 第24页 9、引用已释放的资源 第26页 【案例191】 第26页 10、分配资源是否已正确释放 第28页 案例110.1】 第28页 【案例110.2】 第29页 【案例110.3】 第30页

目 录 一、逻辑类代码问题 第 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 页

案例1104】 第32页 【案例110.5】 第3页 【案例110.6】 第35页 【案例1107】 第38页 防止资源的重复释放 第39页 【案例1111】 第39页 12、公共资源的互斥性和竞用性 第40页 【案例112.1】 第40页 【案例1122】 第40页 第43页 接口类代码问题 1、对函数参数进行有效性检查 第43页 案例21.1】 第43页 【案例212】 第43页 【案例213】 第4页 【案例214】 第46页 【案例215】 第47页 案例216】 第48页 2、注意多出口函数的处理 第49页 案例221】 第49页 第51页 、维护类代码问题 1、统一枚举类型的使用 第51页 案例311】 第51页 注释量至少占代码总量的20% 第51页 【案例321】对XXX产品BAM某版本部分代码注释量的统计 第51页 第52页 四、产品兼容性问题 1、系统配置、命令方式 第52页 案例411】 第52页 【案例41.2】 第53页 2、设备对接 第54页

【案例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 页

案例421】 第54页 其他 第55页 【案例431】 第55页 第58页 五、版本控制问题 1、新老代码中同一全局变量不一致 第58页 案例511】 第58页 第59页 六、可测试性代码问题 1、调试信息打印信息的正确性 第59页 【案例611】 第59页

【案例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、变量指针在使用前就必须初始化 案例111】 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中就是 这样),至少也是被限制使用。而在我们交换机的程序中大量使用指针,并 且有增无减

一、逻辑类代码问题 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、防止指针/数组操作越界 【案例121】 在香港项目测试中,发现ISDN话机拨新业务号码时,若一位一位的拨 至18位,不会有问题。但若先拨完号码再成组发送,会导致MPU死机。 处理过程: 査错过程很简单,按呼叫处理的过程检查代码,发现某一处的判断有误 本应为小于18的判断,写成了小于等于18。 结论 代码编写有误。 思考与启 1、极限测试必须注意,测试前应对某项设计的极限做好充分测试规划。 2、测试极限时还要注意多种业务接入点,本例为ISDN。对于交换机 来说,任何一种业务都要分别在模拟话机、ISDN话机、V5话机、多种形式的话 务台上做测试。对于中继的业务,则要充分考虑各种信令:TUP、ISUP、PRA NO1、V5等等。 【案例122】 对某交换类进行计费测试,字冠011对应1号路由、1号子路由,有4个中继群 1112,13,14(都属于1#模块,前后两个群分别构成自环。其中11,13群向为出中 继,12,14群向为入中继,对这四个群分别进行计费设置,对出入中继都计费。电 话60640001拨打01160010001两次,使四个群都有机会被计费,取话单后浏览话 单发现对11群计费计次表话单出中继群号不正确,其它群的计次表中出中继群号 正常。 处理过程 与开发人员在测试组环境多次重复以上步骤,发现11群的计次表话单有时正

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拨打01160010001两次,使四个群都有机会被计费,取话单后浏览话 单发现对11群计费计次表话单出中继群号不正确,其它群的计次表中出中继群号 正常。 处理过程: 与开发人员在测试组环境多次重复以上步骤,发现11群的计次表话单有时正

常,有时其出中继群号就为一个随机值,发生异常的频率比较高。为什么其它群 的话单正常,唯独11群不正常呢?11群是四个群中最小的群,其中继计次表位于 缓冲区的首位,打完电话后查询内存发现出中继群号在内存中是正确的,取完话 单后再查就不正确了 结论: 话单池的一个备份指针 Pool head1和中继计次表的头指针重合,影响到第 个中继计次表的计费。 思考与启示: 随机值的背后往往隐藏着指针问题,两块内存缓冲区的交界处比较容易出现 问题,在编程时是应该注意的地方 【案例123】 【正 文】 在接入网产品A测试中,在内存数据库正常的情况下的各种数据库方 面的操作都是正常的。为了进行数据库异常测试,于是将数据库内容人为地破坏 了。发现在对数据库进行比较操作时,出现程序跑死了现象 经过跟踪调试发现问题出现在如下一段代码中 I for(F0; KpSysHead->dbf count; 1++) pDBFat=( NM DBFAT STRUC *(NVDB BASE+ DBFAT OFFSET+1 DBFAT LEN) if(fat check(pDBFat)I=O) 456789 pSysHead->system flag =0; head sumo continue:

常,有时其出中继群号就为一个随机值,发生异常的频率比较高。为什么其它群 的话单正常,唯独11群不正常呢?11群是四个群中最小的群,其中继计次表位于 缓冲区的首位,打完电话后查询内存发现出中继群号在内存中是正确的,取完话 单后再查就不正确了。 结 论: 话单池的一个备份指针Pool_head_1和中继计次表的头指针重合,影响到第一 个中继计次表的计费。 思考与启示: 随机值的背后往往隐藏着指针问题,两块内存缓冲区的交界处比较容易出现 问题,在编程时是应该注意的地方。 【案例1.2.3】 【正 文】 在接入网产品A测试中,在内存数据库正常的情况下的各种数据库方 面的操作都是正常的。为了进行数据库异常测试,于是将数据库内容人为地破坏 了。发现在对数据库进行比较操作时,出现程序跑死了现象。 经过跟踪调试发现问题出现在如下一段代码中: 1 for(i=0; idbf_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 }

if(strlen(dbf->dbf name)!=0 & strncmp(dbf->dbf name, pDBFat->dbf name, strlen(dbf->dbf name)==0) 123456 dbf ptrI=( UC *)pDB Fat->dbf head filesize=pDB Fat->dbf fsize, 在测试时发现程序死在循环之中,得到的错误记录是" Bus error"(总线 出错),由此可以说明出现了内存操作异常。 经过跟踪变量值发现循环变量i阀值 pSysHead-> dbf count的数值为 0 XFFFFFFFF,该值是从被破坏的内存数据库中获取的,正常情况下该值小于127。 而 pDBFat是数据库的起始地址,如果 pSysHead-> dbf count值异常过大,将导致 pDBFat1值超过最大内存地址值,随后进行的内存操作将导致内存操作越界错误, 因而在测试过程中数据库破坏后就出现了主机死机的现象。 上面的问题解决起来很容易,只需在第一行代码中增加一个判断条件即可, 如下 for(i=0; ipSysHead->dbf coun & i< MAX DB NUM: i++) ∥ MAX DB NUM=127 这样就保证了循环变量i的值在正常范围内,从而避免了对指针 pDBFat进行 内存越界的操作 从上面的测试过程中,我们可以看到:如此严重的问题,仅仅是一个简单的 错误引起的。实际上,系统的不稳定往往是由这些看似很简单的小错误导致的。 这个问题给我们教训的是:在直接对内存地址进行操作时,一定要保证其值的合 法性,否则容易引起内存操作越界,给系统的稳定性带来潜在的威胁 【案例124】

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; idbf_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 Msg CB FAR pMsg memcpy(( UC *)&tmp msg, pMsg, sizeof(tmp msg); pMsg=pMsg+ - sizeof( tmp msg)/ sizeof(tmp msg=10本意是想移动10个字 节,可是实际上指针移动了10* sizeof(struct MscE)个字节; CelINum=tmp msg. usCelNum 所以结构指针传入函数后,如要进行指针移动操作,最好先将其转化为 UC型再说。总之指针操作要小心为上 3、避免指针的非法引用 【案例131】 【正 文】 在一次测试中,并没有记得做了什么操作,发现 HONET系统的主机复位 了,之后,系统又工作正常了。由于没有打开后台的跟踪窗口,当时查了半天没 有眉目。过了半天,现象又出现了,而且这次是主机在反复复位,系统根本无法

近日在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板配置了 MNTMLT端口, 但是没有做DSL端口之间的半永久数据 于是在程序中不断加打印语句,通过后台的 DBWIN调试程序跟踪,最后 终于定位为:每当执行到 portal. c的 Devicedslmsgproo(O函数中处理U口透传的 if( SPC STATE OK = pSpcCB->bySpcState 语句时,主机复位。但是该语句似乎并无不妥 再分析整个函数, pSpcCB在函数前部分已经被赋值 pSpcCB= SpcCB+(PortTable+index)->spcNo 但由于得到 index后,没有任何判断,导致若 MNTMLT端口没有做半永久, 端口激活后,执行此部分函数,( PortAble+ index)-> spaNo有可能为NUL_WORD, 于是,运算后, pSpcCB可能为非法值。此时主机在取进行判断,就不知会导致 什么后果了。 其实,改起来很简单,只要在这两句前增加一个判断就行了。于是,修改 代码为: if((PortTable+index)-spc No NULL WORD pSpcCB SpcCB+( PortTable+index)->spcNo if( SPC STATE OK = pSpcCB->bySpcState 修改后,问题不再重现 经过分析可以发现,编译环境是有很大的容许空间的,若主机没有做充分 的保护,很可能会有极严重的随即故障出现。所以编程时一定要考虑各种可能情

正常工作了。 我凭记忆,判断应该是与当时正在测试的DSL板的端口配置有关。于是将 板上所有端口配置为普通2B+D端口,重新加载在主机数据,现象消失。于是初 步定位为主机在DSL端口处理过程中有重大错误。 我在新的数据上努力恢复原出问题的现象,却一直没有重现,于是恢复原 数据,加载后立即重现。并注意到,当DSL端口激活时,主机复位。仔细比较两 种数据的差别,发现出现主机复位问题的数据中DSL板配置了MNT/MLT端口, 但是没有做DSL端口之间的半永久数据。 于是在程序中不断加打印语句,通过后台的DBWIN调试程序跟踪,最后 终于定位为:每当执行到portdsl.c的DeviceDslMsgProc()函数中处理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 ) {。。。} } 修改后,问题不再重现。 经过分析可以发现,编译环境是有很大的容许空间的,若主机没有做充分 的保护,很可能会有极严重的随即故障出现。所以编程时一定要考虑各种可能情

点击下载完整版文档(DOC)VIP每日下载上限内不扣除下载券和下载次数;
按次数下载不扣除下载券;
24小时内重复下载只扣除一次;
顺序:VIP每日次数-->可用次数-->下载券;
共70页,可试读20页,点击继续阅读 ↓↓
相关文档

关于我们|帮助中心|下载说明|相关软件|意见反馈|联系我们

Copyright © 2008-现在 cucdc.com 高等教育资讯网 版权所有