I've recently started working on developing APIs written in C. I see some subroutines which expect 8(Eight) parameters and to me it looks ugly and cumbersome passing 8 parameters while calling that particular subroutine. I was wondering if something more acceptable and cleaner way could be implemented .
8 could be a proper number. or it could be that many of those 8 should all belong to a proper class as members, then you could pass a single instance of the class... hard to tell just by this kind of high level discussion.
edit: in c - classes would be similar to structures in this case.
Large numbers of arguments in a function call are usually showing up a design problem. There are ways of apparently reducing the number of parameters, by such means as creating structures which are passed instead of individual variables or having global variables. I'd recommend you DON'T do either of these things, and attend to the design. No quick or easy fix there, but the people who have to maintain the code will thank you for it.
If the API seems cumbersome with that many parameters, use a pointer to a structure to pass parameters that are related in some way.
I'm not going to judge your design without seeing it firsthand. There are legitimate functions that require a large number of parameters, for example:
- Filters with a large number of polynomial coefficients.
- Color space transforms with sub-pixel masks and LUT indices.
- Geometric arithmetic for n-dimensional irregular polygons.
There are also some very poor designs that lead to large parameter prototypes. Share more information about your design if you seek more germane responses.
If a number of arguments can be logically grouped together you may consider creating a structure containing them and simply pass that structure as an argument. For example instead of passing two coordinate values x and y you could pass a POINT
structure instead.
But if such a grouping isn't applicable, then any number of arguments should be fine if you really need them, although it might be a sign that your function does a little too much and that you could spread work over more, but smaller functions.
One pattern used by some APIs (like pthreads
) is "attribute objects" that are passed into functions instead of a bunch of discrete arguments. These attribute objects are opaque structures, with functions for creating, destroying, modifying and querying them. All in all this takes more code than simply dumping 10 arguments to a function, but it's a more robust approach. Sometimes a bit of extra code that can make your code much more understandable is worth the effort.
Once again, for a good example of this pattern, see the pthreads
API. I wrote a lengthy article on the design of the pthreads
API a couple of months ago, and this is one of the aspects I addressed in it.
It also seems to be interesting to consider this question not from the standpoint of ugliness/not ugliness but from the point of performance.
I know that there are some x86 calling conventions that can use registers for passing two first arguments and stack for all other arguments. So I think that if one use this type of calling convention and always use a pointer to structure to pass arguments in situations when a function needs more then 2 parameters in overall the function call might be faster. On Itanium registers are always used for passing parameters to a function.
I think it might be worth testing.
Yes, 8 is almost certianly too much.
Here's some old-school software engineering terms for you. Cohesion and coupling. Cohesion is how well a subroutine holds together on its own, and coupling is how clean the interfaces between your routines are (or how self-sufficient your routines are).
With coupling, generally the looser the better. Interfacing only through parameters ("data coupling") is good low coupling, while using global variables ("common coupling") is very high coupling. When you have a high number of parameters, what is usually the case is that someone has tried to hide their common coupling with a thin veneer of data coupling. Its bad design with a paint job.
With cohesion, the higher (more cohesive) the better. Any routine that modifies eight different things is also quite likey to suffer from low cohesion. I'd have to see the code to see for sure, but I'd be willing to bet that it would be very difficult to clearly explain what that routine does in a short sentence. Sight unseen, I'd guess it is temporally cohesive (just a bunch of stuff that needs to be done at roughly the same time).