瑞星卡卡安全论坛技术交流区系统软件 【转载】软件开发人员必备工具书 【代码大全】

«910111213141516   15  /  16  页   跳转

【转载】软件开发人员必备工具书 【代码大全】

在同一程序中同时使用它们来命名两个变量,就非常容易引入某些难以察觉的错误。
避免使用含义不同但拼写相似的名称。如果发现两个变量名称拼写相似但含义不同,那应
对其中一个重新命名或改变缩写技术,比如ClientsRecs和ClientsReps这样的名称就应避免。因
为它们之间只有一个字母不同,而且这一字母很难辨别,两个名称之间至少应有两个字母不同,
或者把不同的字母放在词首或词尾。如用ClientRecords 和ClientsReports 来分别代替上述两个
名称显然要好得多。
避免使用发音相同或相近的名称。如Wrap和rap。因为这将使你在与同事讨论问题时遇到
很多麻烦。
避免在名称中使用数字。如果变量名中的数字的确很有意义的话,应使用数组而不应使用
单个变量。如果使用数组不合适的话,那么使用含有数字的变量名更不合适。比如,应避免使
用FILE1、FILE2和Total1、Total2 这类名字。可以用很多办法来区分两个变量,但不要采用在
变量名末尾加数字的方法。我不敢说应绝对禁止在变量名中使用数字,但起码你应尽全力避免
这种用法。
避免在名称中改写字母。记住单词的拼写是一件困难的事情,而记住改了字母的单词则更
困难。例如,通过改写字母把highlight 写成hilite 以节省三个字母,将使得读者很难记住这个
单词被改写成什么样了,是Hilite,还是Hai-a-lai-t?谁知道呢?
避免常见的容易拼写错的单词。Absense、acummulate、acsend、calender、conceive、defferred、
definate、independance、occassionally、prefered、reciept、superseed等是英语中经常容易拼写错
误的,绝大多数英语词典中都列有常见的容易拼写错的单词。应避免在变量名中使用这些单词,
以避免因拼写错造成程序中的错误。
不要单纯通过大写来区分变量名。如果使用的是可以区分大小的语言,可能会试图用Frd
来代替fired,用FRD来代替final review duty,用frd 来代替full revenue disbursal,应放弃这种
做法。尽管每个名字都是唯一的,但其中每个名称所代替的意义则是任意且容易混淆的。谁能
知道Frd,FRD和frd 分别对应的是fired,final review duty和full revenue disbursal而不是按其
它顺序来对应的呢?
避免使用标准子程序名和已定义的变量名。所有的语言都要求保留其标准子程序名和已
定义变量名,应注意避免使用这些子程序和变量。比如,下面这段代码在PL/I中是合法的,但
若你真的这样的话,那你一定是一个十足的傻瓜:
if if = then then
then = else;
else else = if;
不要使用与变量所代表的实体没有任何联系的名字。像Margaret或Coolie之类的变量名事
实上保证了除你之外没有其它任何人能理解它的。不要用你的女朋友、妻子或朋友的名字作为
变量名,除非这个程序是关于你的男朋友、妻子或朋友的。即使真的是这样的话,你也应该意
识到他们是有可能变化的,因此用通用些的名字如:BoyFriend、wife或FavoriteBeer会更好。
避免使用含有难以辨认字符的变量名称。要知道有些字符是非常相象的,很难把它们区分
开来。如果两个变量名的唯一区分便是一个或两个这种字符,那么你区分这些变量时就会感到
gototop
 

十分困难。例如,请尝试一下把下表每一组中与其它两个变量名不同的一个找出来。
变量名表
EyeChart1 EyeChartI EyeChart1
TTLCONFUSION TTLC0NFUSION TTLCONFUSION
Hard2Read HardzRead Hard2Read
GRANDTOTAL GRANDTOTAL 6RANDTOTAL
Ttl5 TtlS TtlS
如上表所示,难以区分的字符有"l"和"1"、"1"和"I"、"."和","、"0"和"o";"S"和"5" 、"G"
和"6"等。
9.8  小结
· 恰当的变量名是可读性好的必要条件之一。特殊的变量如循环变量和状态变量要予以
特殊考虑。
· 命名约定可以区分局部、模块和全局变量。同时它还可以区分类型名称,比如可以对
命名常量、枚举类型和变量加以区分。
· 不管你从事的是哪种项目,都应该采用命名约定。所采用的命名约定取决于程序的规
模和从事这一程序的程序员的人数。
· 匈牙利约定是一种非常有效的命名约定,比较适于大规模项目和程序。
· 在现代编程语言中几乎不需要采用缩写技术。
9.8.1  检查表
通用命名约定
· 变量名称是否完全准确地描述了变量代表的是什么?
· 变量名是否指向是客观世界中的问题,而不是关于这问题的用程序语言表达解决方案?
· 变量名称是否是够长,使得你不必破译它?
· 变量名中如果含有计算限定词的话,是否将其放在最后?
· 是否在名称中用Count或Index来代替了Num?
对特殊类型数据的命名
· 循环变量的名称是有意义的吗?(如果循环体较长是嵌套循环的话,应用有含义的名
称来代替i、j、k 之类的名称)
· 是否用更富于含义的名称来代替了被叫作"tempotarg"的临时变量?
· 当逻辑变量的值是"True"时,它的名称是否充分表达了其含义?
· 是否用前缀或后缀来表明了某些枚举类型是一类的?如用Color 来作ColorRed,
ColorGreen,ColorBlue等枚举类型的前缀。
· 命名常量的名称是否是指向它们代表的实体而不是它们所代表的数值的?
命名约定
· 命名约定是否区分了局部、模块和全局数据?
gototop
 

· 命名约定是否对类型名称、命名常量、枚举类型和变量进行了区分?
· 在不支持强化仅供子程序输入参数的语言中,命名约定是否对这类参数进行了标识?
· 命名约定是不是与程序语言的标准约定尽可能地相容?
· 对于语言中没有强制的子程序中仅做输入的参数,是否约定将它标识了?
· 是否对名称进行了格式化以增强程序的可读性?
短名称
· 代码是否使用了长名称?(除非有必要使用短名称)
· 是否避免了只省略一个字母的缩写?
· 所有单词保持缩写的连续性了吗?
· 所有的名称都是容易发音的吗?
· 是否避免了会引起错误发音的名称?
· 是否在注释表中对短变量名进行了注释?
避免如下这些常见的命名错误了吗
· 易引起误会的名称
· 含义相似的名称
· 仅有一或两个字母不同的名称
· 发音相似的名称
· 使用数字的名称
· 对单词作改写以使其比较短的名称
· 英语中常拼写错的名称
· 标准库子程序或已定义的变量名又定义了
· 完全是随意的名称
· 含有难以辨识字母的名称
gototop
 

第十章  变  量
目录
    10.1  作用域
    10.2  持久性
    10.3  赋值时间
    10.4  数据结构与控制结构的关系
    10.5  变量功能单一性
    10.6  全局变量
    10.7  小结
相关章节
    生成数据:见第8 章
    数据命名:见第9 章
    使用基本数据类型:见第11 章
    使用复杂数据类型:见第12 章
    格式化数据说明:见18.5 节
    说明数据:见19.5 节
   
    由于前面一章叙述的都是数据名称问题,你可能会认为恰当地命名变量之后便完事大吉了。
绝非如此!命名仅仅是开始,你使用变量的方法也是非常重要的。
    如果你是个富有经验的程序员的话,那么本章的内容对你尤其有用。在你完全清楚替代方
案之前,很容易在开始时使用有害的技术。然后,即使在你知道如何避免它们时,出于习惯仍
会继续使用它们。有经验的程序员们将会发现10.5 节“变量功能单一性”和10.6 节“全局变
量”的讨论对他们来说是非常有趣的。
10.1    作用域
    作用域指的是变量名称的影响范围,也可称之为可见性,即在程序中某一变量被知道和提
及的范围。作用域有限或很小的变量只在程序的一小部分中被知道,如:一个只有在一个小循
环中用到的循环变量。作用域大的变量则在程序中的许多地方被知道,如:在一个程序中被到
处使用的雇员信息表。
    不同的语言处理作用域的方式是不同的。在Basic 某些实现中,所有变量都是全局的。因
此在这种情况下你无法对变量作用域进行任何控制,这也是Basic 的主要缺点之一。在C 中,
变量可以是对块(用大括号括起来的部分)可见的,也可以是分别对子程序、源文件或整个程
序可见的。在Ada中,变量可以分别是对块、亚程序、包、任务、单元或整个程序中可见的。
    以下是一些关于作用域(可见性)的常用准则:
gototop
 

尽可能减小作用域。你所采取的方法往往取决于你“方便性”和“可管理性”这两个问题
的看法。许多程序员喜欢用全局变量。因为全局变量存取很方便而且程序员们不必围着参数表
和模块命名规则转。事实上,这种存取方便性是与由全局变量引入的危险共存的。
    另一些程序员则尽可能使用局部变量,因为局部变量可以提高可管理性。你所隐含的信息
越多,那么需要记在心中的东西就越少,而需要记住的东西越少,那么犯错误的机会也就越少,
因为许多细节都不需要再进行记忆了。
    “方便性”和“可管理性”之间的区别可以理解为是强调写程序还是强调读程序。扩大变
量作用域事实上的确可以方便写程序,但是一个任意子程序都可以在任意时刻访问任一个变量
的程序,往往要比使用模块化子程序的程序难懂得多。在这种程序中,你无法单纯理解一个子
程序,你必须同时也理解与这个子程序分享全局变量的其它子程序。这样的程序不仅难读,而
且也很难调试和修改。
    因此,你必须尽可能地减小变量的作用域。如果能将变量的作用域限制在一个子程序之内
的话,那是再好不过的了,如果你无法把它限制在一个模块中的话,那就利用存取子程序来使
几个模块分享这一数据。总之,应尽量避免使用全局变量以减小作用域。
    把对某一变量的引用集中放置。某些研究人员认为把对某一变量的访问放得越近,那么对
程序阅读者的精神压力也就越小。这一想法有很大的直觉吸引力——你每次只需注意比较少的
变量。以下是由这一想法产生的几项准则:
    应恰好在某一循环前初始化循环中用到的变量,而不是在含有这个循环的子程序开头对其
中用到的变量进行初始化。这样作可以使你在修改循环时,同时想起对相应的变量的初始化进
行修改;或者在这一循环外再嵌套一个循环时,此时外部循环每执行一次时,都会对内部循环
用到的变量进行初始化,而不会出现只初始化一次的错误。
    要在用到某一变量时才对它进行赋值。你可能有过费尽心机地寻找某一变量到底是在哪被
赋值的体验。因此,越清楚地表示出变量赋值的地方越好。
    下例指出了在一个计算日收入的子程序中,是怎样把对同一变量的引用集中放置,以便方
便地寻找它们的。第一个例子是违反这一原则的一个C语言子程序:
void SummarizeData(...)

...
...
GetOldData(OldData, &NumOldData);
GetNewData(NewData, &NumNewData);
TtlOldData = Sum(OldData,NumOldData);
TtlNewData = Sum(NewData,NumNewData); 语句使用两组变量
PrintOldDataSummary(OldData,TtlOldData,NumO1dData);
PirntNewDataSummary(NewData,TtlOldData,NumNewData);
SaveOldDataSummary(TtlOldData,NumOldData);
SaveNewDataSummary(TtlNewData,NumNewData);
...
...


在上例中,你不得不同时注意 OldData、NewData、NumOldData、NumNewData、TtlOldData
gototop
 

和TtlNewData六个变量,而且又是在这样短的一段程序中。下面的例子指出了如何把这一数量
减少到只有三个:
void SummariseDaily( ... )
{
GetOldData(OldData, &NumOldData);
TtlOldData = Sum(OldData, NumOldData);
PrintOldDataSummary(OldData,TtlOldData,NumOldData);
SaveOldDataSummary (TtlOldDataNumOldData);
...
GetNewData( NewData, &NumNewData);
TtlNewData = Sum( NewData, NumNewData);
PrintNewDataSummary( NewData,TtlNewData,NumNewData);
SaveNewDataSummary( TtlNewData, NumNewData );
...
}
   
    如果像上例这样把程序分用两块,那么每一块都要比原来的块要短,而且其中的变量也要
少得多。这两个块都很容易理解,而且如果需要把这段程序分成几个子程序的话,两个具有较
少变量的块本身就是定义得很好的子程序。
10.2    持久性
“持久性”指的是某一数据的使用寿命。持久性有几种表现形式。如下所示:
·  与某一个块或子程序的生存期一样长。C中的auto变量或Pascal中的局部变量就属       
于这种情况。
·  其生存期取决于你的意愿。Pascal中用New()产生的变量直到dispose()它们时才失效。
在C中用malloc()产生的变量也将持续到free()它们时才失效。
·  与程序的生存期一样长。绝大多数语言中的全局变量都属于这种情况。比如c中的static
变量和 Turbo Pascal中“类型化的常量”(类型化常量是对Pascal的非标准推广)。
·  永远有效。这些变量可能包括你在程序再次执行之间存储在数据库中的变量。例如,
在一个交互式的程序中用户可以定义屏幕的颜色,可以把这些颜色存在一个文件中,
在每次程序加载时再将其调出,现在有少数几种语言支持这种持久性。
    假定的某个变量的持久性要长于其实际持久性时,就会出现问题。变量就像放在冰箱中的
牛奶,你认为它可以保存一星期,但有时可以保存一个月,有时则五天就坏了。变量的持久性
也是同样不可测的。当变量的有效生存期已经结束时,还试图重新使用它,它还会保持原值吗?
有些情况下变量中的值已经被改变了。这可以使你意识到自己的错误,而在另一些情况下,计
算机还让变量保持原值,从而让你认为自己正确地使用了变量。
    以下是可以使你避免这种错误的几个步骤;
    ·  在程序中加入调试代码来检查变量的值是否合理。如果不合理的话。产生一个警告
使用OldData的语句
使用NewData 的语
gototop
 

信息来提示检查不恰当的变量初始化。
    ·  在写代码时假定变量已经失效。比如,退出子程序时某一变量等于某个值,当再次进
入子程序时不要假定这个变量仍保持原值。当然,当你用语言的特定功能来使变量保
持原值时这一原则不适用,比如用C 中的static如来实现这一功能。
·  养成在恰好使用某一变量之前对其进行初始化的习惯。如果发现使用的变量附近没有
对它的初始化,那么你就要小心了。
10.3    赋值时间
    一个对程序的维护性和可读性有深远影响的主题是“赋值时间”——把变量的值和变量联
系在一起的时间。是在写程序时把它们联系在一起?还是在编译、加载或者程序运行时把它们
联系在一起?
    应该尽可能地晚一些将它们联系在一起。通常,越是晚一些给变量赋值,代码的灵活性便
越大。下面是在可能的最早时间——程序写成时对变量进行赋值例子(用C写成):
TestID=47;
    由于47是一个程序的常数值,因此在代码写好时47便与TestID联系在一起了。像上例那样
编码赋值的想法是很有害的,因为如果当这里的47改变时,程序其余用到47且必须与TestID的
值相同的地方很可能会出现语法错误。
    以下是一个稍晚些赋值的例子,即在编译时进行赋值:
#define MAX_ID 47
...
TestID = MAX_ID;
    MAX_ID是一个宏或是命名常量,当编译时编译程序会用一个值来代替它。如果所用的语
言支持这种用法的话,应尽量这样用,因为这种方法要好于前面的用47来硬性赋值。它使得改
变MAX_ID值变得很容易,因为你只需要在一个地方作出改动就可以了,而且不会影响程序性
能。
下面是在最后时刻赋值的例子,即在运行时赋值。
TestID = MaxID;
    程序中MaxID是一个在程序运行时被赋值的变量。这样做的灵活性和可读性也要好于前面
的硬性编译赋值。下面是另一个在运行时赋值的例子:
TestID = ReadFileForMaxID();
    上例中的ReadFileForMaxID()是一个在程序运行时从一个文件中读取数值的子程序。这一
例子假定在程序开始运行之前要用到的值已经被放在文件中了。显然这样作的灵活性和可读性
也要好于前述的硬性编码赋值的例子。不必通过改动程序来改变TestID的值,而只要改动一下
存储该值的文件就可以了。这种方法常用于用户可以定义应用环境的交互式系统中,用户的定
义被存储在一个文件中,当程序运行时从文件中读取定义。
    下面是在程序运行时进行赋值的最后一种形式:
TestID = GetMaxIDFromUser();
上例中GetMaxIDFromUser()是一个采用交互方式从用户那里读取数值的子程序。这种方
gototop
 

法的可读性和灵活性要远远好于硬性编码赋值。为改变TestID值根本不需作出任何改动,只要
在程序运行时由用户输入另外一个值就可以了。从上述在运行时赋值的例子可以看出,即使同
样是在运行时赋值的方式,变量与其值联系到一起的具体时间也是不同的。最后一个例子中的
赋值可以在程序运行中任一时刻进行,它取决于用户被要求输入TestID值的时间。
10.4    数据结构与控制结构的关系
    许多研究者都曾试图努力找出数据结构与控制结构之间的通用关系,这其中最成功的是英
国计算机学家 Michael Jackson。Jackson的技术,主要是通过一种系统的方法把数据结构变换为
控制结构。他的方法在欧洲得到了充分发展并被广泛应用。本书无法详细论述Jackson的理论,
但可以对这种理论所基于的数据和控制流之间的调节关系作一概述。
从可用的数据和输出该是什么样子的想法开始
然后对程序进行定义,使其把输入转化为输出
   
    Jackson勾画出了三种类型数据与相应的控制结构之间的关系。
    程序中顺序性数据可以转化为顺序性语句。数列是由一组按某一特定顺序使用的数据组成
的。如果用排成一列的五条语句来处理五个不同的数值,那么它们就是顺序性语句,如果需要
从某一文件只读取雇员的名字、社会保险号码、地址、电话号码和年龄等五个数据,那你将在
程序中使用顺序性语句来从文件中读取这些顺序性数据。
程序中的选择性数据可以转换为if和case语句。通常,选择性数据指的是在任一特定时刻,
几个数据中的某一个会出现——将选定其中的某一个数据。相应的程序必须用If-Then-Else语句
或Case语句进行选择操作。比如在一个工资发放系统中,你可能需要按某一雇员是按小时计酬

附件附件:

下载次数:214
文件类型:application/octet-stream
文件大小:
上传时间:2006-8-25 17:04:49
描述:



gototop
 

继续

附件附件:

下载次数:210
文件类型:application/octet-stream
文件大小:
上传时间:2006-8-25 17:09:28
描述:



gototop
 

真实的数据可能是上述几种类型数据的组合,这时可以用上述几种操作的组合处理复杂的
数据结构。
10 .5  变量功能单一性
    可以通过几种“巧妙”的办法使变量具有一个以上的功能,但最好不要使用这种所谓的巧
妙办法。
    应使每一个变量只具有一个功能。有时人们会试图在两个不同的地方使用同一变量来进行
两个不同的活动。通常,变量名对其中的一个活动来说是不恰当的,或者在两种情况下都充当
了“临时变量”的角色(且是用无意义的X或Temp来命名的)。下面给出了一个用C语言写成的
一个临时变量具有两个功用的例子:
/* Compute roots of a quadratic equation.
第十章变量147
This code assumes that ( b * b - 4 * a * c ) is positive. */

Temp = sqrt(b * b - 4 * a * c);
root[0] = (-b + Temp)/(2 * a);
root[1] = (-b - Temp)/(2 * a);
    ...
    /* swap the roots */

Temp = root[0];
root[0] = root[1];
root[1] = Temp;
    这段程序的问题是:头几行代码中的Temp与后几行代码中的Temp是什么关系呢?事实上它
们之间没有任何关系,可是,这样使用它会使人们误以为它们之间存在着某种联系,从而产生
困惑,以下是对上面程序的改进:
     
/* Compute roots of a quadratic equation.
This code assumes that (b^2 - 4 * a * c) is positive. */

Discriminant = sqrt(b * b - 4 * a * c);
root[0] = (-b + Discriminant)/(2 * a);
root[1] = (-b - Discriminant)/(2 * a);
...
/* swap the roots */
Oldroot = root[0];
root[0] = root[1];
root[1] = Oldroot;
    避免使用具有隐含意义的变量。一个变量具有一个以上功用的另一种情况是同一变量取值
不同时,其代表的意义也不同。如变量PageCount代表是已经打印的页数,但当它等于-l时则表
示发生了错误;变量CustomerID代表的是顾客号码,但当它的值超过500,000时,你要把
CustomerId的值减掉500,00O以得到一个过期未付款的帐号;而BytesWritten一般表示的是某一输
出文件的字节数,但当其值为负时,则表示的是用于输出磁盘驱动器数目。
    应避免使用上述具有隐含意义的变量。技术上把这种滥用称之为“混合关联”。使用同一变
量来承担两项任务意味着对其中一项任务来说变量类型是错误的。比如上例中的PageCount,在
正常情况下代表页数时是整型的,而当它等于-1表示发生了错误时,则是把整型变量当作逻辑
型来用了。
    即使你清楚这种用法,别人也往往很难理解。如果用两个变量来分别承担两项工作的话,
其意义的清晰性将会使你感到满意,并且,也不会在存储上有额外的麻烦。
保证所有说明的变量。与用一个变量来承担两项工作相反的另一个极端是根本不用它,而
研究表明未被使用的变量往往是与出错率高相联系的。因此,要养成确实用到每一个说明变量
的习惯。某些编译程序会对说明但未用到的变量给出警告。
gototop
 
«910111213141516   15  /  16  页   跳转
页面顶部
Powered by Discuz!NT