C中子程序的参数数量的最佳实践

时间:2010-07-02 13:07:15

标签: c argument-passing

我最近开始研究用C语言编写的API。我看到一些子程序需要8个(8个)参数,而且在调用该特定子程序时,它看起来很丑陋,传递8个参数。我想知道是否可以实施更可接受和更清洁的方式。

9 个答案:

答案 0 :(得分:6)

如果可以在逻辑上将多个参数组合在一起,您可以考虑创建一个包含它们的结构,并简单地将该结构作为参数传递。例如,您可以传递POINT结构,而不是传递两个坐标值 x y

但是如果这样的分组不适用,那么如果你确实需要它们,那么任何数量的参数都应该没问题,尽管它可能表明你的函数做得太多而且你可以将工作分散到更多,但功能较小。

答案 1 :(得分:5)

函数调用中的大量参数通常会出现设计问题。通过诸如创建传递而不是单个变量或具有全局变量的结构的方式,存在明显减少参数数量的方法。我建议你不要做其中任何一件事,并参加设计。没有快速或简单的修复,但必须维护代码的人会感谢你。

答案 2 :(得分:4)

是的,8几乎太过分了。

这里有一些老式的软件工程术语。内聚和耦合。 Cohesion是子程序自身保持在一起的程度,coupling是例程之间的接口是多么干净(或者你的例程是多么自给自足)。

通过耦合,通常越松散越好。仅通过参数(“数据耦合”)的接口是良好的低耦合,而使用全局变量(“公共耦合”)是非常高的耦合。当你有大量的参数时,通常的情况是有人试图用薄薄的数据耦合隐藏它们的公共耦合。它的糟糕设计与油漆工作。

有凝聚力,越高(更有凝聚力)越好。任何修改八种不同事物的例程也很容易受到低内聚的影响。我必须看到代码才能确定,但​​我愿意打赌,很难清楚地解释那个例程在短句中的作用。看不见,我猜它在时间上是凝聚力的(只是需要在大致相同的时间完成的一堆东西)。

答案 3 :(得分:2)

8可能是一个合适的数字。或者可能是这8个人中的许多人都应该属于一个合适的班级作为成员,那么你可以传递一个班级的实例......很难通过这种高级别的讨论来说明。

编辑:在c中 - 类在这种情况下类似于结构。

答案 4 :(得分:1)

我也建议使用结构。 也许您想重新考虑您的API设计。

请记住,开发人员将使用您的API,并且很难使用8参数函数调用。

答案 5 :(得分:0)

如果API对于那么多参数看起来很麻烦,请使用指向结构的指针以某种方式传递相关的参数。

如果不直接看到它,我就不会判断你的设计。有合法的函数需要大量参数,例如:

  1. 具有大量多项式系数的滤波器。
  2. 使用子像素掩码和LUT索引进行颜色空间转换。
  3. n维不规则多边形的几何算法。
  4. 还有一些非常糟糕的设计会导致大型参数原型。如果您寻求更多密切关系,请分享有关您的设计的更多信息。

答案 6 :(得分:0)

某些API(如pthreads)使用的一种模式是“属性对象”,它们被传递给函数而不是一堆离散参数。这些属性对象是不透明的结构,具有创建,销毁,修改和查询它们的功能。总而言之,这需要的代码多于简单地将10个参数转储到函数中,但它是一种更强大的方法。有时,一些额外的代码可以让您的代码更容易理解,值得付出努力。

再一次,有关此模式的一个很好的示例,请参阅pthreads API。几个月前我在pthreads API的设计上写了a lengthy article,这是我在其中提到的方面之一。

答案 7 :(得分:0)

从丑陋/不丑的角度考虑这个问题似乎也很有趣,但从表现的角度来看。

我知道有一些x86 calling conventions可以使用寄存器传递两个第一个参数,并为所有其他参数堆栈。所以我认为如果使用这种类型的调用约定并且总是使用指向结构的指针来传递参数,当函数需要多于2个参数时,函数调用可能会更快。在Itanium寄存器上始终用于将参数传递给函数。

我认为值得测试。

答案 8 :(得分:0)

你可以做的另一件事是将一些参数转换为状态。 OpenGL函数具有较少的参数,因为您有如下调用:

glBindFramebuffer( .. ) ;
glVertexAttribPointer( .. ) ;
glBindTexture( .. ) ;
glBindBuffer( .. ) ;
glBindVertexArray( .. ) ;

// the actual draw call
glDrawArrays( .. ) ;

所有这些(glBind*类型调用)代表“改变状态”,所有这些都将影响下一次绘制调用。想象一下20个参数的绘图调用..绝对无法管理!

用于绘图的旧Windows C api也具有状态,存储在“不透明指针”对象(HDCHWND的内部...)中。不透明指针基本上是C使您无法直接访问的私有数据成员的方式。例如,在Windows绘图API中,您将通过createDC创建一个HDC不透明指针。您可以通过设置DC的内部值 SetDC*函数,例如SetDCBrushColor

现在您已经设置了带有颜色和所有内容的DC,您可以使用Rectangle功能绘制到DC中。您传递了HDC作为第一个参数,其中包含有关使用哪种颜色画笔的信息等。Rectangle则只需要5个参数,hdc,x,y,宽度和高度。