Casting function ptrs

Chris Torek chris at mimsy.UUCP
Fri May 20 00:16:47 AEST 1988


In article <281 at marob.MASA.COM> daveh at marob.MASA.COM (Dave Hammond) writes:
>Given a list of varying typed functions,

Danger Will Robinson :-)

`Varying typed' should trigger alarm bells.

>their names and addresses ... and a routine which is passed a function
>name in order to lookup and return its associated address ...
>How does one declare the lookup function, the return address variable and
>call the returned function, while properly casting the function return value?

Depending on the type variation, there may not be a `proper cast'.
Some types may be mixed (e.g., pointers, via `void *' per the dpANS,
or integral types, via the longest of the bunch).  If there is no
common type, you must use a union:

	/* function-pointer union */
	union fpu { /* abbreviation `f.u.' avoided for obvious reasons :-) */
		long	(*ifn)(void);	/* for integral functions */
		double	(*fn)(void);	/* for floating functions */
		void	*(*ptrfn)(void);/* for object-pointer functions */
		void	(*(*codefn)())();/* for code-pointer functions */
		void	*(*(*pcfn)())();/* for ptr valued code-ptr fns */
		/* &c ad nauseam */
	};
	struct ftable {
		char	*name;		/* the function's name */
		int	type;		/* its return type */
		union	fpu fn;		/* and its address */
	};

Alas, you cannot initialise a union except via its first member,
and that only in dpANS-conformant compilers.

Assuming that all the functions return pointers, you can resort to
this (dropping the prototypes):

	typedef void *PTR;	/* or char *, if void * fails */
	/* optional: */
	typedef PTR (*PFP)(); /* ptr to function returning generic ptr */

	unsigned *a();
	char *b();
	double *c();

	enum ftype { F_UNSIGNED, F_CHAR, F_DOUBLE };
	struct ftable {
		char	*name;
		enum	ftype ftype;
		PTR	(*fn)();	/* or PFP fn */
	} ftable[] = {
		"a",	F_UNSIGNED,	(PTR (*)())a,	/* or (PFP)a */
		"b",	F_CHAR,		(PTR (*)())b,	/* etc */
		"c",	F_DOUBLE,	(PTR (*)())c
		0
	};

>I'm doing it like so:
>
>unsigned *lookup_func();
>unsigned *(*func)();
>char *retp;
>
>if ((func = lookup_func("foo")) != (unsigned *)0) {
>    if (( retp = (char *) (*func)() ))
>	printf("retp=%s",retp);
>    }

Try
	/* clearest: */
	PFP	lookup_func();
	/* expanded one level: */
	/* PTR (*lookup_func())(); */
	/* whole hog: */
	/* void *(*lookup_func())(); */

	PFP	func;
	char	*retp;

	/* also make sure we get the right type back: */
	if ((func = lookup_func("foo", F_CHAR)) != NULL)
		if ((retp = (char *)(*func)()) != NULL)
			printf("retp=%s", retp);

One might wonder, given the less clear `lookup_func' declarations
above, where the arguments go:

	void *(*lookup_func(name, type))()
		char *name;
		enum ftype type;
	{
		register struct ftable *p;

		for (p = ftable; p->name != NULL; p++) {
			if (p->ftype != type)
				continue;
			if (strcmp(p->name, name) == 0)
				return (p->fn);
		}
		return (NULL);
	}

It is rather simpler to write

	PFP lookup_func(name, type)
		char *name;
		enum ftype type;
	{ ...

as I think everyone will agree :-) .
-- 
In-Real-Life: Chris Torek, Univ of MD Comp Sci Dept (+1 301 454 7163)
Domain:	chris at mimsy.umd.edu	Path:	uunet!mimsy!chris



More information about the Comp.lang.c mailing list