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

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

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

好的编译程序应该可以这样: 可以把屡次出错的合法的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. Linux安装SQLite轻量级数据库

    SQLite,是一款轻型的数据库,是遵守ACID的关系型数据库管理系统,它包含在一个相对小的C库中.它是D.RichardHipp建立的公有领域项目.它的设计目标是嵌入式的,而且目前已经在很多嵌入式产 ...

  2. PHP中的密码加密的解决方案

    层出不穷的类似事件对用户会造成巨大的影响,因为人们往往习惯在不同网站使用相同的密码,一家“暴库”,全部遭殃 一般的解决方案 1.将明文密码做单向hash $password = md5($_POST[ ...

  3. PHP基于Sphinx+Swcs中文分词的全文的检索

    简介 Sphinx是开源的搜索引擎,它支持英文的全文检索.所以如果单独搭建Sphinx,你就已经可以使用全文索引了 但是有些时候我们还要进行中文分词所有scws就出现了,我们也可以使用Coreseek ...

  4. SVN访问版本库精细的权限控制

    SVN精细权限控制本章将详细介绍前一章所涉及的两个配置文件, svnserve.conf 和 authz.conf,通过对配置逐行的描述,来阐明其中的一些细节含义.除此之外的其他配置.安装等内容,不是 ...

  5. HDUOJ---2110

    Crisis of HDU Time Limit: 3000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Tot ...

  6. 为Github 托管项目的访问添加SSH keys

    为了便于访问远程仓库,各个协作者将自己的本地的项目内容推送到远程仓库中,使用 SSH keys 验证github的好处:不用每次提交代码时都输入用户名和密码. 如果SSH key没有添加到github ...

  7. IE浏览器中,设置指定程序查看源文件

    第一步:     先按Ctrl+R,输入regedit进入注册表     依次找到 "HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Internet Explo ...

  8. oc 调用c语言方法和oc的方法调用

    //c语方的方法 void sayHello(){ printf("Hello OC"); } int main(int argc, char * argv[]) { sayHel ...

  9. .NET中那些所谓的新语法

    .NET中那些所谓的新语法之四:标准查询运算符与LINQ 摘要: 开篇:在上一篇中,我们了解了预定义委托与Lambda表达式等所谓的新语法,这一篇我们继续征程,看看标准查询运算符和LINQ.标准查询运 ...

  10. C# GridView 给某行或某列绑定点击事件和鼠标事件

    protected void GridViewEx1_RowDataBound(object sender, GridViewRowEventArgs e) { if (e.Row.RowType = ...