Arrays of functions - calling them with different number of args.

Chris Torek chris at mimsy.umd.edu
Wed Mar 7 19:54:45 AEST 1990


In article <8553 at cbnewsh.ATT.COM> ijk at cbnewsh.ATT.COM (ihor.j.kinal) writes:
[existing calls and functions of the form]
>			action_tbl [ action_ind ] ( one_arg )
>Now, I want to add some functions that will have two arguments.
>The question is, how do I express the call to that function
>both simply and portably?

There is no simple, portable method.  Indeed, even the obvious approach:

>Obviously, I could provide a list of arguments for each function
>in my table, and I could test if an arg two is present, then I call
>
>			action_tbl [ action_ind ] ( one_arg, two_arg )
>
>and otherwise, call the old way.  This seems incredibly clumsy.

(which is indeed rather clumsy) is not truly portable, not under ANSI C.
The reason is that `action_tbl' must have one of the two types

	sometype (*action_tbl[SIZE])(type1 arg1);

or

	sometype (*action_tbl[SIZE])(type1 arg1, type2 arg2);

It cannot have both, save by being a union.  Fortunately, all pointers
to functions have the same underlying size, so you can get away with
using one of these types, and applying casts to force the other type
to match.  That is:

	int f0(char *);	/* a one-arg fn */
	int f1(char *);	/* another one-arg fn */
	int f2(int *, int *); /* a two-arg fn */

	int (*action_tbl[3])(char *) = {
		f0,
		f1,
		(int (*)(char *))f2
	};

		...
		if (i < 2)	/* calling f0 or f1 */
			ret = (*action_tbl[i])(char_star_arg);
		else		/* calling f2 */
			ret = (*(int (*)(int *, int *))action_tbl[i])(
				int_star_arg_1, int_star_arg_2);

>Alternately, I could call EVERY function with two arguments,
>with the second being null for the actual one-arg functions.

This requires adding a dummy argument to all the one-arg functions . . .

>Note that I don't want to go back to the source and add a dummy argument
>to all the old functions.

. . . as you supposed.

>What I really want is to construct an arg list and pass that to my
>function call, but I can't figure how to do that.

There is no such option.  It would be nice, but it does not exist.

As an alternative to the example above, the table can be made of a
union, or a structure containing a union.  Unfortunately, it then cannot
be initialised usefully (at least, not without using casts).

One alternative is to require that all functions take one argument
always.  Functions that could use two must instead receive the address of
a structure containing the two desired arguments.  For instance:

	typedef char *pointer;	/* void * in ANSI C */

	int f2(pointer arg0) {
		struct a { int *a1, *a2; } *args = (struct a *)arg0;
		... work with args->a1 and args->a2 ...
	}

The latter is quite similar to the way the Unix kernel handles arguments
to system calls.
-- 
In-Real-Life: Chris Torek, Univ of MD Comp Sci Dept (+1 301 454 7163)
Domain:	chris at cs.umd.edu	Path:	uunet!mimsy!chris



More information about the Comp.lang.c mailing list