just_a_coder

  博客园 :: 首页 :: 博问 :: 闪存 :: 新随笔 :: 联系 :: 订阅 订阅 :: 管理 ::

第一章   假想的编译程序

    几条重要的准则

    1.每条准则都有例外

    2.使用编译程序所有的可选警告设施

        gcc -Wall 

        在原型中使用更精确的类型

    3.使用lint来查出编译程序漏掉的错误

        lint扫描c源文件并对源程序中不可移植的代码提出警告。

    4.如果有单元测试,就进行单元测试

第二章 自己设计并使用断言

    1.才用两个版本,一个用于调试,增加较多的检查,遇到问题及时发现。另一个是交付版本,但是要保证调试代码不在最终产品中出现。

    2.要使用断言对函数参数进行确认

    3.要从程序中删去无定义的特性

    4.详细说明不清楚的断言

 ??5.消除所作的隐式假定,或者利用断言检查其正确性

    6.利用断言来检查不可能发生的情况

    7.在进行放错性程序设计时,不要隐瞒错误

    8.要利用不同的算法对程序的结果进行确认

    9.不要等待错误发生,要使用初始检查程序

第三章 为子系统设防

      1.消除随即特性,使错误可再现

    2.如果某件事甚少发生的话,设法使其经常发生

  3.保存调试信息,以便进行更强的错误检查

  4.建立详尽的子系统检查并且经常地进行这些检查

  5.仔细设计程序的测试代码,任何选择都应该经过考虑

  6.努力的做到透明的一致性检查

  7.不要把对交付版本的约束应用到相应的调试版本上要用大小和速度来换取错误检查能力。

  8.调试版本的速度大约应该是相应交付版本的一半

第4章 对程序进行逐条跟踪

  1.在编写或修改程序的时候最有可能发现错误!!!

  2.不要等到出了错误再对程序进行逐条跟踪

  3.对每一条代码路径进行逐条跟踪

  4.逐条跟踪能发现的错误。上溢和下溢错误;数据转换错误;差1错误;NULL指针错误;使用废料内存单错误(0xA3类错误);用 = 代替 == 的赋值错误;运算优先级错误;逻辑错误。

  5.当对代码进行逐条跟踪时,要密切注视数据流。

  6.源级调试程序可能会隐瞒执行的细节,对关键部分的代码要进行汇编指令级的逐条跟踪

第五章 糖果机界面

  1.要使用户不容易忽视错误情况,不要在正常的返回值中隐藏错误代码。

  2.要不遗余力地寻找并消除函数界面中的缺陷(隐藏的错误)

  3.不要编写多种功能集于一身的函数,为了对参数进行更强的确认,要编写功能单一的函数。

  4.不要模棱两可,要明确地定义函数的参数

  5.编写函数使其在给定有效的输入情况下不会失败

  6.使程序在调用点明了易懂;要避免布尔参数

  7.编写注解突出可能的异常情况

第六章 风险事业

  1.假如将一程序员置于悬崖边,给他绳子和滑翔机,他会怎样从悬崖上下来呢?是沿绳子爬下来呢?还是乘滑翔机呢?还是干脆直接跳下来呢?是沿绳子爬下来还是使用滑翔机我们说不太准,但可以肯定,他不会跳下来,因为那太危险了。可是当程序员有几种可能的实现方案时,他们却经常只考虑空间和速度,而完全忽视了风险性。如果程序员处于这样的悬崖边而又忽视了风险性,只考虑选择到达崖底最有效的途径的话.结果又将如何呢?

  2.使用有严格定义的数据类型(为了具备可移植性)

  3.经常反问:这个变量表达式会上溢或下溢吗?

  4.尽可能精确地实现设计,近似地实现设计就可能出错

  5.一个“任务”应一次完成

  6.前两条原则前面叙述过了:“不要接受具有特殊意义的参数”,例如NULL指针;“按照设计来实现而不能近似地实现。”第三个新的原则是:努力使每个函数一次就完成住务。

  7.避免无关紧要的if语句

  8.避免使用嵌套的“?:”运算符

  9.每种特殊的情况只能处理一次

  10.避免使用有风险的语言惯用语(移位等)

  11.关心局部效率是不值得的。如果你很注重效率的话,请集中于全局效率和算法的效率上,这样你才会看到努力的效果。

  12。不能毫无必要地将不用类型地操作符混合使用,如果必须将
不同类型地操作符混合使用,就用括号把它们隔离开来

  13.避免调用返回错误的函数

第7章 编码中的假象

  1.只引用属于你自己的存储空间

  2.只有系统才能拥有空闲的存储区,程序员不能拥有

  3.指向输出的指针不是指向工作空间缓冲区的指针

  4.不要利用静态(或全局)量存储区传递数据

  5.不要写寄生函数

  6.不要滥用程序设计语言

  7.紧凑的C代码并不能保证得到高效的机器代码

  8.为一般水平的程序员编写代码

第8章 剩下来的就是态度问题

  1.错误几乎不会“消失”

  2.马上修改错误,不要推迟到最后
  3.修改错误要治本,不要治表

  4.除非关系产品的成败,否则不要整理代码

  5.不要实现没有战略意义的特征

  6.不设自由特征

  7.不允许没有必要的灵活性

  8.在找到正确的解法之前,不要一味地“试”,要花时间寻求正确的解

  9.少试多读

  10.尽量编写和测试小块代码。即使测试代码会影响进度,也要坚持测试代码

  11.测试代码的责任不在测试员身上,而是程序员自己的责任

  12.不要责怪测试员发现了你的错误

  13.建立自己优先级列表并坚持之(效率并不是最重要的,相反他的优先级不会很高)

附录A 编码检查表
本附录给出的问题列表,总结了本书的所有观点。使用本表的最好办法是花两周时间评审一下你的设计和编码实现。先花几分钟时间看一看列表,一旦熟悉了这些问题,就可以灵活自如地按它写代码了。此时,就可以把表放在一边了。
一般问题
── 你是否为程序建立了DEBUG版本?
── 你是否将发现的错误及时改正了?
─一 你是否坚持彻底测试代码.即使耽误了进度也在所不惜?
── 你是否依靠测试组为你测试代码?
─一 你是否知道编码的优先顺序?
─一 你的编译程序是否有可选的各种警告?
关于将更改归并到主程序
─一 你是否将编译程序的警告(包括可选的)都处理了?
── 你的代码是否未用Lint
─一 你的代码进行了单元测试吗?
─一 你是否逐步通过了每一条编码路径以观察数据流?
─一 你是否逐步通过了汇编语言层次上的所有关键代码?
── 是否清理过了任何代码?如果是,修改处经过彻底测试了吗?
─一 文档是否指出了使用你的代码有危险之处?
── 程序维护人员是否能够理解你的代码?
每当实现了一个函数或子系统之时
─一 是否用断言证实了函数参数的有效性?
─一 代码中是否有未定义的或者无意义的代码?
─一 代码能否创建未定义的数据?
─一 有没有难以理解的断言?对它们作解释了没有?
─一 你在代码中是否作过任何假设?
─一 是否使用断言警告可能出现的非常情况?
─一 是否作过防御性程序设计?代码是否隐藏了错误?
─一 是否用第二个算法来验证第一个算法?
─一 是否有可用于确认代码或数据的启动(startup)检查?
─一 代码是否包含了随机行为?能消除这些行为吗?
── 你的代码若产生了无用信息,你是否在DEBUG代码中也把它们置为无用信息?
── 代码中是否有稀奇古怪的行为?
── 若代码是子系统的一部分,那么你是否建立了一个子系统测试?
── 在你的设计和代码中是否有任意情况?
── 即使程序员不感到需要,你也作完整性检查吗?
── 你是否因为排错程序太大或太慢,而将有价值的DEBUG测试抛置一边?
── 是否使用了不可移植的数据类型?
─一 代码中是否有变量或表达式产生上溢或下溢?
── 是否准确地实现了你的设计?还是非常近似地实现了你的设计?
── 代码是否不止一次地解同一个问题?
── 是否企图消除代码中的每一个if语句?
── 是否用过嵌套?:运算符?
── 是否已将专用代码孤立出来?
── 是否用到了有风险的语言惯用语?
─一 是否不必要地将不同类型的运算符混用?
── 是否调用了返回错误的函数?你能消除这种调用吗?
─一 是否引用了尚未分配的存储空间?
─一 是否引用已经释放了的存储空间?
── 是否不必要地多用了输出缓冲存储?
── 是否向静态或全局缓冲区传送了数据?
── 你的函数是否依赖于另一个函数的内部细节?
── 是否使用了怪异的或有疑问的C惯用语?
── 在代码中是否有挤在一行的毛病?
── 代码有不必要的灵活性吗?你能消除它们吗?
─一 你的代码是经过多次“试着”求解的结果吗?
─一 函数是否小并容易测试?
每当设计了一个函数或子系统后
─一 此特征是否符合产品的市场策略?
─一 错误代码是否作为正常返回值的特殊情况而隐藏起来?
─一 是否评审了你的界面,它能保证难于出现误操作吗?
─一 是否具有多用途且面面俱到的函数?
─一 你是否有太灵活的(空空洞洞的)函数参数?
─一 当你的函数不再需要时,它是否返回一个错误条件?
─一 在调用点你的函数是出易读?
─一 你的函数是否有布尔量输入?
修改错误之时
── 错误无法消失,是否能找到错误的根源?
─一 是修改了错误的真正根源,还是仅仅修改了错误的症状?

posted on 2010-04-05 22:56  justacoder  阅读(330)  评论(0编辑  收藏  举报