编译程序只能查找出程序的语法错误,而对于“数组越界訪问”,“对空指针解引用”等错误。编译程序是束手无策的。同一时候我们知道測试人员所使用的黑箱測试方法所能做的不过往程序里填数据,并看它弹出什么。这就决定了对程序错误的检測可能须要点运气。

假如编译程序可以检測出“数组越界訪问”,“差一错误”,“空指针”等等错误,那么编写无错代码事实上就要简答多了。

所以我们须要一个思维转变: 不要光依赖黑箱測试方法。还应该试着去模仿前面所讲的假想编译程序,来排除运气对程序測试的影响,自己主动地抓住错误的每一个机会。

好的编译程序应该可以这样: 可以把屡次出错的合法的C习惯使用方法看成程序中的错误。这句话什么意思呢? 一些C使用方法从语法上讲是合法的,可是往往却给程序带来意想不到的错误。所以好的编译程序应该提供支持:让我们把这些使用方法当成错误。

举个样例:

/* memcpy 复制一个内存块 */

void* memcpy(void *pvTo,void *pvFrom, size_t size)
{
byte *pbTo=(byte *) pvTo;
byte *pbFrom=(byte *)pvFrom;
while(size-->0);
*pbTo++=*pbFrom++;
return pvTo;
}

编译程序会让这个程序愉快地通过编译,可是程序执行后我们可能须要花费大量时间才干调试出这个很隐藏的错误:while条件推断语句之后多了一个分号。这导致循环体为空语句。这显然不是程序猿的意图。可是编译器却无法检測出这个错误。由于空语句从语法角度上是合法的。

虽然在C语言中空语句本身是合法的,可是我们的确非常少这样使用,出现空语句时往往是因为程序猿不小心导致的。而这样的空语句也会导致隐藏非常深的错误。所以当出现空语句时,假设编译器把它觉得是个错误。并自己主动给我们一个警告,这样让我们非常easy查找出错误。

当然假设我们的确要使用空语句时,那就用。

可是最好使用NULL使其明显可见。NULL仅仅是个常量,所以编译程序不会为NULL语句生成不论什么代码。

这样,编译程序仅仅接受显示的NULL语句,而把隐式的空语句(即仅仅有一个分号)标示为错误。

这就使得我们既能够明白地使用空语句,同一时候又能够指示出那些隐式的往往导致错误的空语句。

另一种常见的问题就是无意的赋值。比如

if(ch=‘\t')
ExpandTab();

我们是想推断ch是否和‘\t’相等,却导致‘\t’赋值给ch。这导致程序的行为和我们期望的大相径庭。可是编译器却不会给出不论什么抱怨,由于这是合法的C语句。所以某些编译程序同意用户在&& 和 || 表达式以及if,for, while构造的表达式中禁止使用简单赋值。这样就能够帮助用户查出这样的错误。这样做的基本根据就是用户极有可能在以上五种情况下把“==”打成“=”。

可是有时为了代码的简单性,我们可能编写出下面代码

while(*pchTo++=*pchFrom++)
NULL;

所以此时为了避免警告信息,我们能够这样编写

while((*pchTp++=*pchFrom)!='\0')
NULL;

这样做虽然看上去要麻烦。可是现代的商业级编译器不会为这样的的冗余代码产生额外的代码,会把它优化掉。同一时候又能够降低风险。更加安全。

空语句。错误的赋值以及原型检查等仅仅是很多C编译程序提供的选择项中的一小部分内容。实际上还有很多其它的选择项。这里的要点是:用户能够选择的编译程序警告设施能够就可能的错误向用户发出警告信息。虽然有时为了这些警告设施,我们可能须要一些额外的工作,可是我们应该把这些警告设施看成一种无风险高偿还的程序投资。

使用编译程序全部的可选警告设施。

还有一种检查错误更具体。更彻底的方法是使用lint。lint这个工具最初是用来扫描C源文件并对源程序中不可移植的部分提出警告,如今的lint有用程序变得更加严谨,lint能够检測出尽管可移植而且全然合乎语法但非常有可能是错误的特性。

使用lint来检查出编译程序漏掉的错误。

有时,似乎能够跳过一些设计用来避免程序出错的步骤,比如单元測试。可是走捷径之时。就是麻烦将至之日。

假设有单元測试,就进行单元測试。



总结: 当你敲代码时,要在心中时刻牢记着假想编译程序这一概念,这样就能够花费非常少力气利用每一个机会抓住错误。

要考虑编译程序产生的错误。lint产生的错误以及单元測试失败的原因。消除程序错误的最好方法是尽可能早。尽可能easy地发现错误。要寻求费力最小的自己主动差错方法。

最后用作者在本章里的一句引言结束这篇文章:

投资者与赌徒之间的差别在于投资者利用每一次机会,不管它是多么小。去争取利益。而赌徒仅仅靠运气。

编程精粹--编写高质量C语言代码(1):假想编译程序的更多相关文章

  1. 编程精粹--编写高质量C语言代码(3):自己设计并使用断言(二)

    接着上一遍文章<<编程精粹--编写高质量C语言代码(2):自己设计并使用断言(一)>>,继续学习怎样自己设计并使用断言,来更加easy,更加不费力地自己主动寻找出程序中的错误. ...

  2. 编程精粹--编写高质量C语言代码(4):为子系统设防(一)

    通常,子系统都要对事实上现细节进行隐藏,在进行细节隐藏的同一时候.子系统为用户提供了一些关键入口点. 程序猿通过调用这些关键的入口点来实现与子系统的通信.因此假设在程序中使用这种子系统而且在其调用点加 ...

  3. <编程精粹:编写高质量C语言代码> 读书笔记

    0.规则<The Elements of Programming Style><The Elements of Style> 1.假想的编译程序(1)使用编译器提供的所有的可选 ...

  4. HTML Inspector – 帮助你编写高质量的 HTML 代码

    HTML Inspector 是一款代码质量检测工具,帮助你编写更优秀的 HTML 代码.HTML Inspector 使用 JavaScript 编写,运行在浏览器中,是最好的 HTML 代码检测工 ...

  5. iOS应用开发最佳实践系列一:编写高质量的Objective-C代码

          本文由海水的味道编译整理,转载请注明译者和出处,请勿用于商业用途! 点标记语法 属性和幂等方法(多次调用和一次调用返回的结果相同)使用点标记语法访问,其他的情况使用方括号标记语法. 良好的 ...

  6. 如何编写高质量的js代码--底层原理

    转自: 如何编写高质量的 JS 函数(1) -- 敲山震虎篇   本文首发于 vivo互联网技术 微信公众号 链接:https://mp.weixin.qq.com/s/7lCK9cHmunvYlbm ...

  7. 如何编写高质量的C#代码(一)

    从"整洁代码"谈起 一千个读者,就有一千个哈姆雷特,代码质量也同样如此. 想必每一个对于代码有追求的开发者,对于"高质量"这个词,或多或少都有自己的一丝理解.当 ...

  8. 怎样编写高质量的java代码

    代码质量概述     怎样辨别一个项目代码写得好还是坏?优秀的代码和腐化的代码区别在哪里?怎么让自己写的代码既漂亮又有生命力?接下来将对代码质量的问题进行一些粗略的介绍.也请有过代码质量相关经验的朋友 ...

  9. 怎样编写高质量的 Java 代码

    代码质量概述 怎样辨别一个项目代码写得好还是坏?优秀的代码和腐化的代码区别在哪里?怎么让自己写的代码既漂亮又有生命力?接下来将对代码质量的问题进行一些粗略的介绍.也请有过代码质量相关经验的朋友提出宝贵 ...

随机推荐

  1. zabbix 介绍

    zabbix实现原理及架构详解想要用好zabbix进行监控,那么我们首要需要了解下zabbix这个软件的实现原理及它的架构.建议多阅读官方文档. 一.总体上zabbix的整体架构如下图所示: 重要组件 ...

  2. iOS-按钮单选与多选逻辑处理

    概述 循环创建按钮, 进行按钮单选或者多选的操作. 详细 代码下载:http://www.demodashi.com/demo/10712.html 我们经常会有多行多列按钮的页面, 这个时候我们通常 ...

  3. Everything:速度最快的文件名搜索工具

    http://xbeta.info/everything-search-tool.htm Everything(官网|中文主页|教程)是速度最快的文件名搜索软件.其速度之快令人震惊,百G硬盘几十万个文 ...

  4. Java虚拟机学习 - JDK可视化监控工具 ( 7 )

    1.JConsole JConsole工具在JDK/bin目录下,启动JConsole后,将自动搜索本机运行的jvm进程,不需要jps命令来查询指定.双击其中一个jvm进程即可开始监控,也可使用“远程 ...

  5. 关于android闹钟,设置定时提醒的一点心得

    首先在设置提醒之前你需要一个入口,比如说onclick事件中,在此不做赘述. android中使用闹钟进行提醒其实非常简单,你只需要告知系统你想在什么时候被提醒,然后需要一个闹钟的广播接收器,当到你设 ...

  6. 记一次400错误引发的血案(URL中特殊符号的转义/400 bad request错误)

    django+nginx+uwsgi部署的站点访问某个URL时发生了400 bad request的错误,而使用django自带的开发版的web server时没有遇到此问题.初步判断是nginx或u ...

  7. Chart.js 学习笔记

    1.引入Chart.js 文件 <script src="Chart.js"></script> 2.在html中创建画布 <canvas id=&q ...

  8. Linux 分区注意事项

    必须分区: 1)/(根分区) 2)/swap(交换分区,当内存不超过4G时,建议swap大小为内存2倍,若超过4G,建议交换分区跟内存一样大) 推荐分区 /boot(启动分区,单独分区,最新200M)

  9. java使用ssh访问Linux的项目jscraft

    一.gradle地址 // https://mvnrepository.com/artifact/com.jcraft/jsch compile group: 'com.jcraft', name: ...

  10. java与数据库交互常用到的一些方法

    下面我整理了一下java中常用的几个与数据库交互的常用方法,仅供参考: 1.执行SQL(dao层的实现类中) (1)SQL查询: //import org.hibernate.Query;//impo ...