首页 新闻 论坛 群组 Blog 文档 下载 读书 Tag 网摘 搜索 开源 FAQ 第二书店 博文视点 程序员
频道: 研发 数据库 中间件 信息化 视频 .NET Java 游戏 移动 服务: 人才 外包 培训
    图书品种:235680
       
热门搜索: ASP.NET Ajax Spring Hibernate Java

How to Use Routine Parameters

如何使用子程序参数

子程序之间的接口是程序中最易出错的部分之一。由BasiliPerricone1984)所做的一项被广为引用的研究发现,程序中有39% 的错误都是属于内部接口错误——也就是子程序间互相通讯时所发生的错误。以下是一些可以减少接口错误的指导原则:

照输入-修改-输出的顺序排列参数  不要随机地或按字母顺序排列参数,而应该先列出仅作为输入用途的参数,然后是既作为输入又作为输出用途的参数,最后才是仅作为输出用途的参数。这种排列方法暗合了子程序的内部操作所发生的顺序——先是输入数据,然后修改数据,最后输出结果。下面给出一些Ada语言中参数列表的示例:

 Ada示例:以输入-修改-输出顺序排列的参数

procedure InvertMatrix(

    originalMatrix: in Matrix;

    resultMatrix: out Matrix

);

...

 

procedure ChangeSentenceCase(

    desiredCase: in StringCase;

    sentence: in out Sentence

);

...

 

procedure PrintPageNumber(

    pageNumber: in Integer;

    status: out StatusType

);

这种排列规则与C函数库中所用的把会被修改的参数列在最前面的规则是不同的。然而对我来说,这种输入-修改-输出的排列规则更有意义,当然,如果你总是统一地采取某种排列规则的话,那么为代码的读者考虑,你还是延用自己的规则为好。

考虑自己创建inout关键字  其他一些现代编程语言并没有像Ada那样支持inout关键字。在使用这些语言的时候,你可能还是可以通过预处理指令来自己创建inout关键字:

C++示例:定义你自己的INOUT关键字

#define IN

#define OUT

void InvertMatrix(

    IN Matrix originalMatrix,

    OUT Matrix *resultMatrix

);

...

 

void ChangeSentenceCase(

    IN StringCase desiredCase,

    IN OUT Sentence *sentenceToEdit

);

...

 

void PrintPageNumber(

    IN int pageNumber,

    OUT StatusType &status

);

在这里,INOUT这两个宏关键字只是起说明性的作用。如果你想让被调用的子程序修改某一个参数的值,那么还是得通过指针或引用参数来传递该参数。


请在应用这一技术之前,请考虑它的以下两种显著弊端。自行定义的INOUT关键字扩展了C++语言,从而在某种程度上让多数阅读这一代码的人感到生疏。如果你以这种方式扩展所用的语言,请确保能够持续一致地使用该方法,最好是在整个项目的范围内。第二个弊端在于编译器并不会强制INOUT关键字的使用,也就是说,你有可能把某个参数标记为IN但仍在子程序中修改了该参数的值。阅读代码的人可能会误认为有关代码是正确的,然而事实上却非如此。使用C++中的const关键字来定义输入参数通常更为适宜

如果几个子程序都用了类似的一些参数,应该让这些参数的排列顺序保持一致  子程序的参数顺序可以产生记忆效应——不一致的顺序会让参数难以记忆。比如说在C语言中,fprintf()函数比printf()函数就是多了一个放在开头的文件参数而已,其他都完全一样。而与之类似的函数fputs(),它比puts()只多了一个放在最后的文件参数。本来应该很容易记住的参数,却因为这点儿毫无道理的可气的区别而变得难以记忆了。

而另一方面,C语言中的strncpy()函数所接受的参数依次是目标字符串、源字符串和最大字节数,memcpy()函数也是接受同样顺序相同的参数。这两个函数的相似性对记住函数中的参数不无裨益。

使用所有的参数  既然往子程序中传递了一个参数,就一定要用到这个参数。如果你不用它,就把它从子程序的接口中删去。未被用到的参数和出错率的增加不无关系。在一项研究中,不出现未被用到的变量的子程序中有46%没有错误,而含有超过一个未被用到的变量的子程序中则仅有17%~29%没有错误(CardChurchAgresti 1986)。

这样去除未被用到的参数的规则也有一个例外。如果你是在一定条件下编译某部分程序,那么就可能只是编译了子程序中使用某个参数的那一部分。对这种做法要慎重,但如果你确信这样可行,那么这样做也没问题。总之,如果你有很好的理由不使用某个参数,那就继续留着它吧。相反,如果你没有很好的理由,那就应该花功夫来清理代码。

把状态或出错变量放在最后  按照习惯做法,状态变量和那些用于指示发生错误的变量应放在参数表的最后。它们只是附属于程序的主要功能,而且它们是仅用于输出的参数,因此这是一种很有道理的规则。

不要把子程序的参数用做工作变量  把传入子程序的参数用做工作变量是很危险的。应该使用局部变量。比如说在下面这段Java程序中,inputVal这个参数就被不恰当地用于存储计算的中间结果:

 Java示例:不恰当的使用输入参数

int Sample( int inputVal ) {

    inputVal = inputVal * CurrentMultiplier( inputVal );

    inputVal = inputVal + CurrentAdder( inputVal );

    ...

    return inputVal;

}

在这段代码中,inputVal这个名字很容易引起误解,因为当执行到最后一行代码时,inputVal包含的已经不是最初的输入值了,它的值是用输入值计算出的结果,因此这个参数名起的不对。如果日后你又要修改这段程序,要在其他地方使用原有的输入值,你可能会想当然地以为inputVal是含有原始输入值的参数并使用它,而事实上并非如此。

该怎样解决这个问题呢?为inputVal换个名字行吗?

查看所有评论(0)条】

最近评论



正在载入评论列表...
热点评论