程序设计实践----编程风格

本文探讨了程序设计风格的重要原则,强调代码应具备清晰性和简洁性,包括选择有意义的变量名,遵循命名约定,使用明确的表达式和语句,保持一致性,避免函数宏的滥用,并给出关于注释的有效建议。良好的编程风格应成为习惯,以提高代码的可读性和可维护性。
摘要由CSDN通过智能技术生成

     程序设计风格的原则根源于由实际经验中得到的常识,它不是随意的规则或者处方。代码应该是清楚地和简单的——具有直截了当的逻辑、自然地表达式、通行的语言使用方式、有意义的名字和有帮助作用的注释等,应该避免耍小聪明的花招,不使用非正规的结构,一致性是非常重要的东西。

1.1名字

       什么是名字?一个变量或函数的名字标识这个对象,带着说明其用途的一些信息。一个名字应该是非形式的、简练的、容易记忆的,如果可能的话,最好是能够拼读的。许多信息来自上下文和作用范围(作用域)。一个变量的作用域越大,它的名字所携带的信息就应该越多。全局变量使用具有说明性的名字,局部变量用短名字。根据定义,全局变量可以出现在整个程序中的任何地方,因此它们的名字应该足够长,具有足够的说明性,以便使读者能够记得它们是干什么用的。给每个全局变量声明附一个简短注释也非常有帮助。

        人们常常鼓励程序员使用长的变量名,而不管用在什么地方。这种认识完全是错误的,清晰性经常是随着简洁而来的。

        现实中存在许多命名约定或者本地习惯。常见的比如:指针采用以p结尾的变量名,例如nodep;全局变量用大写开头的变量名,例如Global;常量用完全由大写字母拼写的变量,如C O N S T A N T S等。有些程序设计工场采用的规则更加彻底,他们要求把变量的类型和用等都编排进变量名字中。例如用p c h说明这是一个字符指针,用s t r T o和s t r F r o m表示它分别是将要被读或者被写的字符串等。至于名字本身的拼写形式,是使用 n p e n d i n g或P e n d i n g还是n u m _ p e n d i n g,这些不过是个人的喜好问题,与始终如一地坚持一种切实际的约定相比,这些特殊规矩并不那么重要。

        函数采用动作性的名字。函数名应当用动作性的动词,后面可以跟着名词:

        now = date.getTime();

        putchar('\n');
对返回布尔类型值(真或者假)的函数命名,应该清楚地反映其返回值情况。下面这样的语句

        if(checkoctal(c))...

是不好的,因为它没有指名是么时候返回真,什么时候返回假。而:

       if(isoctal(x))...

就把事情说清楚了:如果参数是八进制数字则返回真,否则为假。

1.2  表达式和语句

         名字的合理选择可以帮助读者理解程序,同样,我们也应该以尽可能一目了然的形式写好表达式和语句。应该写最清晰的代码,通过给运算符两边加空格的方式说明分组情况,更一般的是通过格式化的方式来帮助阅读。这些都是很琐碎的事情,但却又是非常有价值的,就像保持书桌整洁能使你容易找到东西一样。与你的书桌不同的是,你的程序代码很可能还会被别人使用。

        用加括号的方式排除二义性。括号表示分组,即使有时并不必要,加了括号也可能把意图表示得更清楚。在上面的例子里,内层括号就不是必需的,但加上它们没有坏处。熟练的程序员会忽略它们,因为关系运算符(< <= == != >= > )比逻辑运算符(& &和| |)的优先级更高。

1.3 一致性和习惯用法

      为了一致性,使用习惯用法。和自然语言一样,程序设计语言也有许多惯用法,也就是那些经验丰富的程序员写常见代码片段的习惯方式。在学习一个语言的过程中,一个中心问题就是逐渐熟悉它的习惯用法。

       常见习惯用法之一是循环的形式。而习惯用法的形式却是:

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

            array[i] = 1.0;

       这并不是一种随意的选择:这段代码要求访问n元数组里的每个元素,下标从0到n-1。在这里所有循环控制都被放在一个f o r里,以递增顺序运行,并使用+ +的习惯形式做循环变量的更新。这样做还保证循环结束时下标变量的值是一个已知值,它刚刚超出数组里最后元素的位置。熟悉C语言的人不用琢磨就能理解它,不加思考就能正确地写出它来。

        对于无穷循环,我们喜欢用:

       for (; ;)...

      但while(1)...

也很流行。请不要使用其他形式。

         缩排也应该采用习惯形式。  

        一致地使用习惯用法还有另一个优点,那就是使非标准的循环很容易被注意到,这种情况常常预示着有什么问题:

1.4 函数宏

      老的C语言程序员中有一种倾向,就是把很短的执行频繁的计算写成宏,而不是定义为函数。完成I / O的g e t c h a r,做字符测试的i s d i g i t都是得到官方认可的例子。人们这样做最根本的理由就是执行效率:宏可以避免函数调用的开销。实际上,即使是在C语言刚诞生时(那时的机器非常慢,函数调用的开销也特别大),这个论据也是很脆弱的,到今天它就更无足轻重了。有了新型的机器和编译程序,函数宏的缺点就远远超过它能带来的好处。 

        函数宏最常见的一个严重问题是:如果一个参数在定义中出现多次,它就可能被多次求值。如果调用时的实际参数带有副作用,结果就会产生一个难以捉摸的错误。

       给宏的体和参数都加上括号。如果你真的要使用函数宏,那么请特别小心。宏是通过文本替换方式实现的:定义体里的参数被调用的实际参数替换,得到的结果再作为文本去替换原来的调用段。

        C++ 提供的在线函数既避免了语法方面的麻烦,而且又可得到宏能够提供的执行效率,很适合用来定义那些设置或者提取一个值的短小函数。

1.5 神秘的数

      神秘的数包括各种常数、数组的大小、字符位置、变换因子以及程序中出现的其他以文字形式写出的数值。

字形式写出的数值。
       (1) 给神秘的数起个名字。作为一个指导原则,除了0和1之外,程序里出现的任何数大概都可以算是神秘的数,它们应该有自己的名字。在程序源代码里,一个具有原本形式的数对其本身的重要性或作用没提供任何指示性信息,它们也导致程序难以理解和修改。下面的片段摘自一个在2 4×8 0的终端屏幕上打印字母频率的直方图程序,由于其中存在一些神秘的数,程序的意义变得很不清楚:



        在这段代码里包含许多数值,如2 0、2 1、2 2、2 3、2 7等等。它们应该是互相有关系的……但是……它们确实有关系吗?实际上,在这个程序里应该只有三个数是重要的:2 4是屏幕的行数;8 0是列数;还有2 6,它是字母表中的字母个数。但这些数在代码中都没出现,这就使上面那些数显得更神秘了。

通过给上面的计算中出现的各个数命名,我们可以把代码弄得更清楚些。我们发现,例如数字3是由( 8 0-1 ) / 2 6得到的,而l e t应该有2 6个项,而不是2 7个(这个超一( o ff - b y - o n e )错误可能是由于写程序的人把屏幕坐标当作从1开始而引起的)。通过一些简化后,我们得到的结果代码是:


        现在,主循环到底做什么已经很清楚了:它是一个熟悉的从0到N L E T的循环,是一个对数据(数组)元素操作的循环。程序里对d r a w的调用也同样容易理解,因为像M A X R O W和M I N C O L这样的词提醒我们实际参数的顺序。更重要的是,现在我们已经很容易把这个程序修改为能够对付其他的屏幕大小或不同的数据了。数被揭掉了神秘的面纱,代码的意义也随之一目了然了。

        把数定义为常数,不要定义为宏。C程序员的传统方式是用# d e f i n e行来对付神秘的数值。C语言预处理程序是一个强有力的工具,但是它又有些鲁莽。使用宏进行编程是一种很危险的方式,因为宏会在背地里改变程序的词法结构。我们应该让语言去做正确的工作 。

       与此类似的还有另一个问题,那就是程序里许多上下文中经常出现的0。虽然编译系统会把它转换为适当类型,但是,如果我们把每个0的类型写得更明确更清楚,对读程序的人理解其作用是很有帮助的。例如,用(v o i d *) 0或N U L L表示C里的空指针值,用‘\ 0’而不是0表示字符串结尾的空字节。

         利用语言去计算对象的大小。不要对任何数据类型使用显式写出来的大小。例如,我们应该用s i z e o f(i n t)  而不是2或者4。基于同样原因,写s i z e o f(a r r a y [ 0 ] ) 可能比s i z e o f(i n t) 更好,因为即使是数组的类型改变了,也没有什么东西需要改变。利用运算符s i z e o f常常可以很方便地避免为数组大小引进新名字。

1.6 注释

       最好的注释是简洁地点明程序的突出特征,或是提供一种概观,帮助别人理解程序。注释应该提供那些不能一下子从代码中看到的东西,或者把那些散布在许多代码里的信
息收集到一起。当某些难以捉摸的事情出现时,注释可以帮助澄清情况。如果操作本身非常明了,重复谈论它们就是画蛇添足了。

        否定性的东西很不好理解,应该尽量避免。

        无论产生脱节的原因何在,注释与代码矛盾总会使人感到困惑。由于误把错误注释当真,常常使许多实际查错工作耽误了大量时间。所以,当你改变代码时,一定要注意保证其中的注释是准确的。

        学生常被告之应该注释所有的内容。职业程序员也常被要求注释他们的所有代码。但是,应该看到,盲目遵守这些规则的结果却可能是丢掉了注释的真谛。注释是一种工具,它的作用就是帮助读者理解程序中的某些部分,而这些部分的意义不容易通过代码本身直接看到。我们应该尽可能地把代码写得容易理解。在这方面你做得越好,需要写的注释就越少。好的代码需要的注释远远少于差的代码。

1.7 为何对此费心

        这里最关键的结论是:好风格应该成为一种习惯。如果你在开始写代码时就关心风格问题,如果你花时间去审视和改进它,你将会逐渐养成一种好的编程习惯。一旦这种习惯变成自动的东西,你的潜意识就会帮你照料许多细节问题,甚至你在工作压力下写出的代码也会更好。





评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值