版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
1、编写优质无错代码http:/LinuxA 01-08-19 21:59 500p ariesram- 一. 引言 八月上旬,深圳举办了一个讨论会,主题是"编写优质无错代码"。这个讨论会吸引了深圳各大软件公司,通信公司的程序员,系统分析员参加,并在讨论会后纷纷表示,这种讨论会很有实际价值,希望将这种形式的讨论会继续下去,形成一个论坛,以提高大家的编程水平和交换有价值的信息资料。
2、; 这个活动的发起是从网络上开始的。我偶然看到了这个讨论会的论题,发生了兴趣。本来周末的我一般是很懒的,没什么事情是不会出门的。而当我看到这论题后,就给举办者发信表示愿意参加。于是,一个周六的下午,我就坐在了讨论会的现场。参加完这个讨论后,我觉得有必要把其中的精华部分写下来,和网络上的广大程序员共享,于是就有了这篇文章。 二.主题: 编写优质无错的代码-讨论会主题。
3、160; 相信每个程序员都有这种希望,谁都不愿意自己写出来的代码在release之后出错,需要不停的修改维护。但是,主持人提出了这样一个问题:"编写优质无错代码是否必要?" 为什么呢?我稍微解释一下。在项目的时间很 紧张的时候,是按期完成任务重要,还是代码的稳定性,优质无错重要呢? 主持人提出的四个具体问题是: 1、编写优质无错的代码的代价是什么? &
4、#160; 2、代码的质量重要还是编写效率重要? 3、在压力的情况下,你会牺牲质量来提高效率么? 4、编写优质无错的代码是否意味着效率的降低? 对于第一个问题,编写优质无错代码的代价当然是时间,不过随着编程人员的经验逐渐丰富,所需要的时间也逐渐减少。对于第二个问题,代码的质量比编写效率重要。当你花了1周时间写出来的代码需要你花一个月或者更长的时间去debug
5、, 去修改错误,这种效率的损失是得不偿失的。对于第三个问题, 这需要看项目经理或者产品经理的态度和专业精神了。如果在一个专业的项目经理或者产品经理的指挥下,当然是首先保证质量其次提高效率。而对于某些项目经理或者产品经理来说,按时完成任务是最重要的,他们往往不在乎在软件发布之后花比开发时间长得多的时间去修改程序,维护错误。因为,对于他们来说,首先是要完成任务,好给上级领导交差,至于后期维护,就是另外一个任务了,维护花的时间多,正说明了他这个项目的复杂性和难度。而对于开发人员来讲,所希望的则正好相反。开发人员不喜欢花太多的时间在一个烂摊子上。所以,在讨论会上,大家纷纷表
6、160; 示,应该让项目经理或者产品经理也来听一听这个讨论会:-)。 对于第四个问题,当然优质无错代码不是意味着效率的降低,而是正好相反,对提高效率有很好的促进作用。一个版本发布之后,如果因为错误太多,开发人员不得不去花很多时间修改bug, 甚至要从系统的体系结构方面去做 大的改动,重新编写部分代码,这种效率的降低才是更大,更不能承受的。而且,花了太多的时间在老版本的维护上,必然影响到新版本的工程进度,直接影响到整个产品线的质量和进度,严重的甚至会毁掉
7、整个产品。 对于这一个主题,我的回答是,在时间允许的范围之内,尽量提高代码的质量,不追求慢工出细活,不追求代码的100%无错,但是要保证99%以上的无错。这样,在时间的压力下,在质量要求的束缚下,就要求程序员有一个良 好的习惯,和稳健的编程风格,以保证代码的优质无错。这就是第二个问题:什么是编写优质无错的代码的核心思想?优质无错是相对的,而不是绝对的。任何代码,都不可能说是绝对无错的,但是在绝大部分情况下,是稳定的,强健的,优质的,无错的。每次发布的时候,都会对上次的发布版本
8、做若干修改,增强功能的同时,也要修改若干bug。那么,核心思想就是:怎样才能自动地查出这个错误。怎样才能避免这个错误。 三.编写优质无错代码的经验 在说了上面很多理论性的问题之后,来看一看具体问题。先来看一看一个具体的题目:(我本人就是先在网上看了这个题目,才对这个讨论会发生兴趣的) 题目1: 作为开发团队的一员,你需要实现一些库函数提供给其他人使用。假设你
9、实现的一个函数原型如下: int DoSomeThing(char* pParam) . 你们约定好参数pParam不能为NULL,但为了防止调用者错误传递NULL,你需要在你的函数里做判断处理。 请问你会选择那种方式,并说明原因?
10、160; (a) if (!pParam) return 0; (b) if (!pParam) return ERROR_PARAM; (c) if (!pParam) pParam = "" &
11、#160; . (d) if (!pParam) throw EXCEPTION_ERROR_PARAM; (e) if (!pParam) MessageBox(.); (f) assert(!pParam); (附加说明一点
12、,基于目前开发人员技术分布情况和参与讨论会的人员的技术分布情况,这次所列举的例子都是C/C+和Java方面的,不涉及到VB, PB, Delphi等语言。不过对于这些程序员,讨论也是有借鉴作用的。)关于这个问题,大概是所有的程序员都会遇到的。所以,在网上和讨论会上,都发生了激烈的争论和意见交换。我大概把主要的几种观点记录了一下,列举在下面: 1、选择f的理由 因为非NULL是约定,所以可以确定是调用者的问题,f可以明确地指出这一点,防止错误扩散。
13、60; 我的附加说明: 防止错误扩散的意思是,如果用其他方式,比如throwexception的方式,这个异常不一定会在调用此函数的上一层被捕捉到,可能会被继续抛出直到最上一层或者直到在某一层被catch到,这样的话,错误就会距离发生地点很远,扩散开来。这一观点,代表了一大部分的程序员的观点。 2、反对用f 不赞成assert, assert更重要的作用是程序体里面的一个注释, 在阅读程序的时候起作用不能依赖他来检测错误, 很大程度上assert容易使
14、使用者依赖它本不应该依赖的东西。 这也代表了部分程序员的观点,认为assert是不可依赖的,而应该依赖于错误检测,比如返回值或者异常。 3、另外一种观点 f和d都可取。如果没有系统开销的考虑,d则更好些。可以一举两得。如果没人catch这个exception,其结果就跟f一样,按bug处理,dump core留下一stack trace。如果有人catch,那就按运行错误处理.但是返回一特初值表示错误,只是将错误上交
15、,掩耳盗铃而已。最终总得有个人assert,messagebox,throwexception,perror+exit,或别得什么的。既然已经是约定,就干脆付起责任。 4、一种反对d的理由 不可用d, 这就像你用人,却不相信人一样,偏要try,catch防范他。其实那个错是自己造成的,如果看到异常就容易不检讨自己。 5、关于观点3的支持意见 讨论过程中,有人
16、认为assert检查的是bug, 而异常是可以恢复的意外情况。所以,观点3的支持者说:可恢复的意外是可以理解的,但可恢复的bug就没什么意义了。既然已经约定好了,你再违背,就属于是bug而不是意外了(比如打不开文件什么的)。很多库函数都不检查指针的合法性(除了系统调用以外,因为总不能让系统dump core吧),也不检查指针是否为NULL(因为如果层层都检查,必定劳民伤财,干脆让最上面调用的人在调用之外查)。 6、选择d+f 选f+d, 好处如下:
17、160; a以最激烈的方式,充分暴露调用都的错误!能及时修改BUG b便于调试,问题出现后,直接到事故现场。比120还快! c对于realse版的代码没有任何副作用。 d以处理的代价来看 采用断言也是编写最小一种。 e它是多语种,多平台所通用的方式, 如:C /C+ VB,Java1.4 在win ,unix通吃, 便于移置!
18、0; 如果在现实中,测试没有能找到所有的BUG,那可能就要用异常来帮忙了! 当然,我也提出了我的观点, 我支持观点6。理由如下: assert只在debug标志的时候有用,而在编译release版本的时候不起作用。assert对于检查硬编码的错误,是非常有用的,能够及时的查处编码的错误。比如borland c+的类库源代码中就有很多这样的assert。但是assert
19、不是万能的,因为有很多错误的发生不是完全在编译时发生的,而是运行时的错误。在release后,assert是不可能依赖的。那么,我们就需要exception这一机制来检测运行时错误,并相应的做出处理。当然,在异常检测和处理过程中还有许多需要讨论的问题,由于不是这一题目的范围,我们没有必要继续讨论得太多,但是,提出来希望大家注意:异常不是捕获了就完成任务了,而要对于不同的情况,采取不同的处理办法,千万不能只是捕获,而不做任何处理,那样和不捕获异常没有任何区别。 在题目刚刚提出的时候,选择各种答案的人都有,所以,我有必要在这里把其他答案为
20、什么不能选的理由说一下。 (a) if (!pParam) return 0; 这是很多初级程序员常常采取的一种方式。返回值设为0。 因为函数的返回值往往是计算的结果,不赞成把错误标志值和计算结果混在一起使用,容易造成使用者的误会。当然,在很多unix函数中,由于历史原因,还存在很多这样子的函数,所以需要指出,不要沿用这种方式。 (b) if (!pPara
21、m) return ERROR_PARAM; b比a稍微好一点点,返回了一个常量或者预定义的宏。 从返回值的字面上,调用者能知道发生了什么错误,但是,这也不是一种好的方法。 (c) if (!pParam) pParam = "" .
22、; 这是最不好的方式。直接给pParam赋予空字符串,然后继续函数过程,这容易造成不可预料的后果,是程序不稳定的根源。 (d) if (!pParam) throw EXCEPTION_ERROR_PARAM; 抛出异常,刚刚已经讨论过了,不再赘述。 (e) if (!pParam) M
23、essageBox(.); 这是一种比较可笑的方式,当然也有不少人用。MessageBox是直接弹出一个对话框,告诉使用者,出错了。但是并不做任何处理,程序继续往下执行,直到出错崩溃。呵呵 (f) assert(!pParam); 断言,刚刚已经讨论过了,不再赘述。 以上这个题目,引发了所有与会者的兴趣,讨论异常热烈,最后,主持人也给出了自己的观点:d+f。
24、当然这并不是标准答案,因为编程这一门课程本来就没有什么标准答案,大家见仁见智,这个答案只是经验的积累。 主持人紧接着列出了"编写优质无错代码的经验": a.理想的编译器和实际的编译器 b.使用断言 c.函数的界面设计 d.考虑风险 &
25、#160; e.态度的问题 以上是本节的主要内容。断言,刚刚的问题中已经讨论过了,来看看其他的内容。 理想的编译器和实际的编译器: 题目二: 下面memcpy函数实现有什么问题: Void *memcpy(void *pvTo,void *pvFrom,size_t size)
26、; byte *pbTo=(byte *) pvTo; byte *pbFrom=(byte *)pvFrom; while(size - >0); *pbTo+= *pbFrom+; return pvTo;
27、; 呵呵,粗略一看,这函数还真找不出问题来。但是仔细看看,你就会发现while(size - >0); 这里多了一个分号,导致下面的*pbTo+= *pbFrom+;不是在while循环中执行多次,而是只执行了一次。当然这不是函数设计者的预期结果,而编译器却不会报告错误,因为while(size - >0);从语法上来讲,并没有错误。这就是理想的编译器和实际的编译器的区别所在。 那么,该怎么检查这种错误呢?主持人提出了如下办法:
28、 while(size - >0) NULL; 可以加入NULL来解决空语句. 这样子,当你需要while(size - >0) *pbTo+= *pbFrom+; 这种形式的时候,就不会发生错误了,只需要用眼睛看看,就能发现了。两点好处 1 无冗余代码,2 使人更明白。减少风险. 还有人会这么写 &
29、#160; if( (n=read(.) = 1) . 在这里,赋值符号=和判断相等的符号=容易敲错,而编译器又检查不出来,可能就会有如下错误: If(ch = ).;这也是需要注意的问题。 理想的编译器和实际的编译器小结: a.把屡次出错的合法的C习惯用法看成程序中的错误 b.增强编译器的警告级别
30、 c.使用其它的工具来检查代码 如 Lint 等 d.进行单元测试 e.消除程序错误的最好方法是尽可能早、尽可能容易地发现错误,要寻求费力最小的自动查错的方法 f.努力减少程序员查错所需的技巧 使用断言 题目三
31、60; 下面函数实现,哪一个好,为什么? a. char Uptolower(char ch) if(ch >= A && ch <= Z) return ch+=a-A; return -1;
32、60; b. char Uptolower(char ch) assert(ch >= A && ch <= Z); if(ch >= A && ch <= Z) return ch+=a-A;
33、 return ch; c. char Uptolower(char ch) assert(ch >= A && ch <= Z); return ch+(a-A);
34、60; 分析: a.该函数检查ch是否在A.Z之间,如果是,则返回相应的小写字符,如果不是,则返回-1。 缺点在于:把错误标志值和计算结果混在一起使用,容易造成使用者的误会。 b.该函数使用了断言,如果ch在A.Z之间则返回相应的小写字符,如果不是,断言会起作用,程序发生错误并退出。而最后一个return ch;则是在release的时候,如果不是A.Z之间,则返回原来的字符。但是,从书写效率
35、上来说,这个函数稍微罗嗦了一点。因为它重复使用了断言和if判断。 c.该函数也使用了断言,返回相应大写字母的小写字母。 使用断言的好处: a.暴露了调用者的错误 b.便于调试 c.对代码没有代价 d.最少的处理代价 &
36、#160; 断言使用举例: void memcpy(void * pvTo,void *pvFrom,size_t size) void *pbTo= (byte *)pvTo; void *pbFrom= (byte * pvFrom); assert(pvTo !=NULL && pvFrom !=NULL);
37、160; assert(pbTo >= pbFrom +size' 'pbFrom >= pbTo+size); 使用断言的规则: a.要使用断言对函数参数进行确认 b.要从程序中删去无定义的特性或者在程序中使 用断言来
38、检查出无定义特性的非法使用 c.不要浪费别人的时间-详细说明不清楚的断言 d.消除所做的隐式假定,或者利用检查其正确性 e.在进行防错性程序设计时,不要隐瞒错误防错性程序设计虽然被誉为有较好的编码风格,但它却隐瞒了错误。 要记住,我们正在谈论的错误决不应该再发生,而对这些错所进行的安全处理又编写无错代码变得更加困难
39、0; f.要利用不同的算法对程序的结果进行确认 g.不要等待错误发生,要使用初始检查程序 断言小结: a.要同时维护交付和调试两个版本。封装交付的版本,应尽可能地使用调试版本进行自动查错。 b.断言是进行调试检查的简单方法。要使用断言捕捉不应该发生的非法情况。不要混淆非法情况与错误情况之间的区别,后者是在最终产品中必须处理的。
40、0; c.使用断言对函数的参数进行确认,并且在程序员使用了无定义的特性时向程序员报警。涵数定义得越严格,确认其参数就越容易。 d.防错性程序设计会隐瞒错误。在进行防错编码时,如果”不可能发生”的情况确实发生了,要使用断言进行报警。 写到这里,我们初步探讨了编写优质无错代码的必要性,原则,和相关经验。 留几个练习题目,大家也参与一下讨论吧。
41、0; 练习题目1: 下面的memset函数实现有什么问题? void *memset(void *pv, byte b, size_t size) byte *pb = (byte *)pv; unsigned long l;
42、 size_t sizeSize; l = (b << 8) | b; /* 用4个字节拼成一个long */ l = (l << 16) | l; pb = (byte *)longfill(long *)pb, l, size/4); size = size % 4; w
43、hile (size- > 0) *pb+ = b; return (pv); 练习题目2: 下面的代码用memset将三个局部变量置为0,请问可能会有什么问题? void DoSomeThing(.)
44、60; int i; int j; int k; memset(&k, 0, 3*sizeof(int); / 将i,j,k置为0 . 练习题目
45、3: 定义结构如下: typedef struct char c1; char c2; int n; stru; 请问
46、sizeof(stru)等于多少?并说明理由。 练习题目4: 下面是C语言中两种if语句判断方式。请问哪种写法更好?为什么? int n; if (n = 10) / 第一种判断方式 if (10 = n) / 第二种判断方式 练习题目5:
47、 下面的代码有什么问题? void DoSomeThing(.) char* p; . p = malloc(1024); / 分配1K的空间 if (NULL = p)
48、0; return; . p = realloc(p, 2048); / 空间不够,重新分配到2K if (NULL = p) return; .
49、0; 练习题目6: 下面的代码有什么问题? char *DoSomeThing(.) char str16; . return str;
50、160; 练习题目7: 下面的代码有什么问题? char *_strdup( const char *strSource ) static char strMAX_STR_LEN; strcpy(str, strSource);
51、; return str; 练习题目8: 下面的代码有什么问题?并请给出正确的写法。 try FILE* fp = fopen("c:1.dat"); if (NULL != fp)
52、 . fclose(fp); except(EXCEPTION_EXECUTE_HANDLER) 编写优质无错的代码(幻灯片完全版)http:/LinuxA 01-08-19 21:59 549p
53、ariesram- 介绍 编写优质无错代码是否必要? 编写优质无错的代码的核心思想 编写优质无错代码的经验 概述 概述各个主题 解释各个单独的主题如何组合在一起
54、0; 编写优质无错的代码是否必要 ? 编写优质无错的代码的代价是什么? 代码的质量重要还是编写效率重要?在压力的情况下,你会牺牲质量来提高 效率么? 编写优质无错的代码是否意味着效率的将低 ? 编写优质无错的代码的核心思想
55、60; 大家是否为提高代码编写代码质量而努力? 习题 怎样才能自动地查出这个错误! 怎样才能避免这个错误! 编写优质无错代码的经验 理想的编译器和实际的编译器 使用断言
56、 函数的界面设计 考虑风险 态度的问题 Void *memcpy(void *pvTo,void *pvFrom,size_t size) byte *pbTo=(byte *) pvTo; byte *pbFrom=(byte *)pvFrom;
57、160; while(size - >0); *pbTo+= *pbFrom+; return pvTo; 在判断中使用无意的赋值。 If(ch = ); 解决的办法:1wile () NULL; 可以加入NULL来解决空语句 ;
58、2 if ( =ch); (strcpy函数的例子) while(*pchTo += *pchForm +) NULL; while(*pchTo+=*pchFrom+)!=) NULL; 两点好处 1 无冗余代码,2 使人更明白。减少风险. 把屡次出错的合法的C习惯用法看成程序中的错误 增强编译器
59、的警告级别 使用其它的工具来检查代码 如 Lint 等 进行单元测试 小结: 消除程序错误的最好方法是尽可能早、尽可能容易地发现错误,要寻求费力 最小的自动查错的方法 努力减少程序员查错所需的技巧
60、0; 使用断言 Char Uptolower(char ch) if(ch >= A && ch <= Z) return ch+=a-A; return -1; Char Uptolower(ch
61、ar ch) assert(ch >= A && ch <= Z); if(ch >= A && ch <= Z) return ch+=a-A; return ch; Char U
62、ptolower(char ch) assert(ch >= A && ch <= Z); return ch+(a-A); 暴露了调用者的错误 便于调试 对代码没有代价
63、160; 最少的处理代价 void memcpy(void * pvTo,void *pvFrom,size_t size) void *pbTo= (byte *)pvTo; void *pbFrom= (byte * pvFrom); assert(pvTo !=NULL && pvFrom !=NULL);
64、60; assert(pbTo >= pbFrom +size' 'pbFrom >= pbTo+size); 要使用断言对函数参数进行确认 要从程序中删去无定义的特性或者在程序中使 用断言来检查出无定义特性的 非法使用
65、 不要浪费别人的时间-详细说明不清楚的断言 消除所做的隐式假定,或者利用检查其正确性 在进行防错性程序设计时,不要隐瞒错误 防错性程序设计虽然被誉为有较好的编码风格,但它却隐瞒了错误。要记住, 我们正在谈论的错误决不应该再发生,而对这些错所进行的安全处理又编写
66、160; 无错代码变得更加困难 要利用不同的算法对程序的结果进行确认 不要等待错误发生,要使用初始检查程序 断言的使用与防错的程序设计冲突么?他们相适应的范围环境在什么呢? 断言小结: 要同时维护交付和调试两个版本。封装交付的版本,应尽可能地使用调试版
67、 本进行自动查错。 断言是进行调试检查的简单方法。要使用断言捕捉不应该发生的非法情况。 不要混淆非法情况与错误情况之间的区别,后者是在最终产品中必须处理的。 使用断言对函数的参数进行确认,并且在程序员使用了无定义的特性时向程 序员报警。涵数定义得越严格,确认其参数就越容易。 防错性程序设
68、计会隐瞒错误。在进行防错编码时,如果”不可能发生”的情况 确实发生了,要使用断言进行报警。 函数的界面 Char *strdup(char *str) Char * strNew; strNew = (char *) maloc (strlen(str)+1); &
69、#160; Strcpy(strNew,str); Return (strNew); Char c ; c=getchar(); if(EOF=c) . void s
70、trdup(const char* strsrc , char * strdes, size_t dessize ); Bool getchar(char * pch); 要使用不容易忽视错误情况,不要在返回值中隐藏错误代码 void * realloc (void * pv , size_t size ); 是一个面面俱到的函数 realloc() cha
71、nges the size of the memory block pointed to by ptr to size bytes. The contents will be unchanged to the minimum of the old and new sizes; newly allocated memory will be uninitialized. If ptr is NULL, the call
72、is equivalent to malloc(size); if size is equal to zero, the call is equivalent to free(ptr). Unless ptr is NULL, it must have been returned by an earlier call to malloc(), calloc() or realloc().
73、60; 不要编写多种功能集于一身的函数 void *memset( void *dest, int c, size_t count ); size_t count=10; int setvalue=0xff; memset(pdest,count,setvalue); cha
74、r *copysubstr (char * strTo, char * strFrom , size_t size) char * strStar= strTo; ASSERT(size<=strlen(strFrom); 我的写法:Void memset( void *dest, byt
75、e c, size_t count ); 不要模棱两可,要明确地定义函数的参数。 编写函数使其在给定有效的输入情况下不会失败(tolower函数) 函数界面小结 设计能够低御错误的界面并不困难,但这确实需要多加考虑并且愿意放弃 根深蒂固的编码习惯。 只需简单地改变函数的界面,就可以使 程序员编
76、60; 写出正确的代码。 关键概念是”尽可能地使一切清晰明了”。 最容易使用和理解的函数界面,是其中每个输入和输出参数都只代表一种 类型数据的界面。把错误码值和其它的专用值混在函数的输入和输出参数 中,只会搞乱函数的界面。 设计函数的界面迫使程序员考虑所有重要细节(如错误情况的处理),不
77、 要使 程序员能够很容易地忽视或者忘记有关的细节。 老要想到程序员调用所编函数的方式,找出可能使程序员无意引入错误码 的界面缺陷。尤其重要的是要争取编出永远成功的函数,使调用者不必进 行相的错误处理。 为了增加程序的或理解性从而减少错误,要保证所编函数的调用能够被必
78、; 须阅读这些调用的程序员所理解。莫明其妙的数字和布尔参数都与这一目 标背道而驰,因此应该给以消除。 分解多功能的函数.取更专业的函数名不但可以增进人们对它理解,而且 使我们可以更加严格的断言自动地检查出调用错误 为了向程序员展示出所编函数的适当调用方法,要在函数的界面中通过注 解的方式详细说明。要
79、强调危险的方面 。 考虑编写代码的风险 如何做才能减少甚至消除风险 程序员忽视风险性。 肓目认为,自已的程序不会错误。程序员不会打算出错。出错后,也不吃 惊。 思想上有,不管作出哪种选择,最后总能得到无错代码。
80、60; Long 的位域有多长,ANSI并没有对些做出标准 使用有严格定义的数据类型 int32 ,_int64,_int16 (windows) 数据上溢与下溢 #define Max=255; unsigned char ch for(ch =0 ; ch <=Ma
81、x; ch+) 经常反问自己: “这个变量或表达式会上溢或下溢吗?” 一个”任务”应一次完成 每个函数只完成它自己的任务 函数要符合它的设计原则:高内聚, 有且只有一个任务。
82、 违反原则,难以调试,测试等。难以阅读。代码难以重复利用 “?:” 运算符也是一种if 语句 使用 “?:” 运算符所存在的问题是:由于它很简单,容易使用,看起来好象 是产生高效代码的理想方法,因此程序员就不再寻找更好的解决方法了。更 严重的是,程序员会将if 版本转换为 “? :” unsigne
83、d uCycleCheckBox(unsigned uCur) reurn (uCur<=1)? (uCur=1)? 2: (uCur+1); 避免使用嵌套的“? :”运算符 每种特殊情况只能处理一次。 (C+的异常处理,结构化异常处理,以及Java 中的机制 finally) &
84、#160; 避免使用有风险的语言惯用语 在某些程序员看来,放弃任何可能获得效率的机会似乎犯罪。要树立:即使效 率可能会稍稍低一点,也要使用安全的设计和实现来系统地减少风险性。 a=a+c/4 为变成 a=a+c>>2; 不一致性是编写正确代码的障碍。
85、急于改正的心里,在没有规约的情况下,会造成很大的混乱。比起没有改进造 成了更大的损失。 编码风格如此,错误处理如此; 避免调用返回错误的函数 在设计函数时尽量避免返回错误值,以免程序员错误地处理或漏掉这些返回值 风险小结 在选择数据类型的时
86、候要谨慎。 由于代码可能会在不理想的硬件上运行,因此很可能算法是正确的而执行起来 却有错。所以要经常详细检查计算结果和测试结果的数据类型范围是否上溢或 下溢。 每函数应该只有一个严格定义的任务,不仅如此,完成每个任务也应只有一种 途径。 If 语句是个警告信号,说明代码所做的工作可能比所需要的要多。努力消除代 码中每一个不必要的if 语句,经常反问自己:”怎样改变设计从而删掉这个特 殊
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 陕西机电职业技术学院《食品安全分析实验》2023-2024学年第一学期期末试卷
- 音乐培训协议合同范例
- 合作设立公司合同范例
- 厂家代加工合同范例
- 橡胶厂房转让合同范例
- 销售锯铣刀合同范例
- 驾驶员合同范例扣分
- 工程设计用工合同范例
- 酒店厨房顾问合同范例
- 销售数控钻铣床合同范例
- 铜材压延生产节能减排关键技术研究
- 500字作文标准稿纸A4打印模板-直接打印
- 16J607-建筑节能门窗
- 高速铁路路基堆载预压施工方案
- 《深圳市综合整治类旧工业区升级改造操作规定》(征求意见
- 注塑作业指导书范本
- 五年级体质健康数据
- 牛津英语9B-课文翻译
- 绿化养护记录表(共2页)
- 真空蒸镀中部分金属熔点及不同气压下蒸发温度
- 中日标准件对照表
评论
0/150
提交评论