代码风格规范

移山之道——VSTS软件开发指南(第2版)》第10.1节  代码风格规范

 

10.1  代码风格规范

代码风格的原则是:简明,易读,无二义性。

提示:这是移山公司的一家之言,如果碰到争执,关键是要本着“保持简明,让代码更容易读”的原则,看看如下争执中的代码规范是否能够让程序员们更好地理解和维护程序。

10.1.1  缩进

是用Tab键好,还是248个空格?

结论:4个空格,在VS2005和其他的一些编辑工具中都可以定义Tab键扩展成为几个空格键。不用 Tab键的理由是Tab键在不同的情况下会显示不同的长度。4个空格的距离从可读性来说正好。

10.1.2  行宽

行宽必须限制,但是以前有些文档规定的80字符行宽太小了(以前的计算机/打字机显示行宽为80字符),现在时代不同了,可为100字符。

10.1.3  括号

在复杂的条件表达式中,用括号清楚地表示逻辑优先级。

10.1.4  断行与空白的{ }

程序的结构是什么风格?下面有几种格式,我们一一讨论。

最精简的格式A

if (condition)    DoSomething();

else     DoSomethingElse();

有人喜欢这样,因为可以节省几行,但是不同的语句(Statement)放在一行中,会使程序调试(DeBug)非常不方便,如果要一步一步观察conditioncondition有可能是包含函数调用的复杂表达式)中各个变量的变化情况,单步执行就很难了。

因此,我们还是要有断行,这样可以得到如下的结构——格式B

if (condition)

    DoSomething();

else

    DoSomethingElse();

这样的结构,由于没有明确的“{”和“}”来判断程序的结构,在有多层控制嵌套的时候,就不容易看清结构和对应关系。下面的改进(格式C)虽好,但是阿超认为还是不够清晰:

if ( condition) {

    DoSomething();

} else {

    DoSomethingElse();

}

是我们最后做了这个选择,每个“{”和“}”都独占一行。就是格式D

if ( condition)

{

    DoSomething();

}

else

{

    DoSomethingElse();

}

10.1.5  分行

不要把多行语句放在一行上。

a = 1; b = 2;       // bogus

if (fFoo) Bar();     // bogus

更严格地说,不要把不同的变量定义在一行上。

Foo foo1, foo2;     // bogus

10.1.6  命名

阿超:我在某个同学的程序中看到有些变量叫“lili”,“yunyun”,不知道这些变量在现实生活中有没有什么意义。

下面哄笑起来。

果冻:(红着脸问)那有些变量的确想不出名字,简单的变量像ijk都用完了,怎么办?

阿超:当我们的程序比“Hello World”复杂10倍以上的时候,像给变量命名这样简单的事看起来也不那么简单了。我们就来谈谈如何起名字这个问题。程序中的实体、变量是程序员昼思夜想的对象,要起一个好的名字才行。大家都知道用单个字母给有复杂语义的实体命名是不好的,目前最通用的,也是经过了实践检验的方法叫“匈牙利命名法”。例如:

fFileExist,表明是一个bool值,表示文件是否存在;

szPath,表明是一个以0结束的字符串,表示一个路径。

如此命名的目的是让程序员一眼就能看出变量的类型,避免在使用中出错。早期的计算机语言(如BCPL)不作类型检查,在C语言中,intbytecharbool大概都是一回事。下面这一句话:

if (i)

从语义来说,i可以是表示真/假的一个值,也可以表示长度是否为零,还可以表示是否到了字符串的结束位置,或者可以表示两个字符串比较的结果不相等(strcmp()返回-101)。从程序的文字上,很难看出确切的语义。

同样是字符串类型,char *BSTR的有些行为是很不一样的。

HRESULT的值也可以用来表示真假,但是HR_TRUE == 0HR_FALSE ==1,这和通常的true/false刚好相反。

大部分的程序,错就错在这些地方!在变量面前加上有意义的前缀,就可以让程序员一眼看出变量的类型及相应的语义。这就是“匈牙利命名法”的用处。

匈牙利命名法的一些通用规定,见本书附录B(第337页)。

还有一些地方不适合用“匈牙利命名法”,比如,在一些强类型的语言(如C#)中,不同类型的值是不能做运算的,对类型有严格的要求,例如C# 中,if()语句只能接受bool值的表达式,这样就大大地防止了以上问题的发生。在这样的语言中,前缀就不是很必要的,匈牙利命名法则不适用了。Microsoft .Net Framework就不主张用这样的法则。

10.1.7  下划线问题

下划线用来分隔变量名字中的作用域标注和变量的语义,如:一个类型的成员变量通常用m_来表示。移山公司规定下划线一般不用在其他方面。

10.1.8  大小写问题

由多个单词组成的变量名,如果全部都是小写,很不易读,一个简单的解决方案就是用大小写区分它们。

Pascal——所有单词的第一个字母都大写;

Camel——第一个单词全部小写,随后单词随Pascal格式,这种方式也叫lowerCamel

一个通用的做法是:所有的类型//函数名都用Pascal形式,所有的变量都用Camel形式。

/类型/变量:名词或组合名词,如MemberProductInfo等。

函数则用动词或动宾组合词来表示,如get/set; RenderPage()

10.1.9  注释

谁不会写注释?但是,需要注释什么?

不要注释程序是怎么工作的(How),你的程序本身就应该能说明这一问题。

//this loop starts the i from 0 to len, in each step, it

// does SomeThing

for (i = 0; i<len; i++)

{
         DoSomeThing();

}

以上的注释是多余的。

注释是用来解释程序做什么(What),为什么这样做(Why),以及要特别注意的地方的,如下:

//go thru the array, note the last element is at [len-1]

for (i = 0; i<len; i++)

{

    DoSomeThing();

}

复杂的注释应该放在函数头,很多函数头的注释都是解释参数的类型等的,如果程序正文已经能够说明参数的类型in/out等,就不要重复!

注释也要随着程序的修改而不断更新,一个误导的(Misleading)注释往往比没有注释更糟糕。

另外,注释(包括所有源代码)应只用ASCII字符,不要用中文或其他特殊字符,它们会极大地影响程序的可移植性。

在现代编程环境中,程序编辑器可以设置各种好看的字体,我们可以使用不同的显示风格来表示程序的不同部分。

 

posted @ 2008-12-02 19:02  博文视点  阅读(1261)  评论(0编辑  收藏  举报