Path: utzoo!attcan!uunet!husc6!purdue!umd5!mimsy!chris From: chris@mimsy.UUCP (Chris Torek) Newsgroups: comp.lang.c Subject: Re: Casting function ptrs Message-ID: <11571@mimsy.UUCP> Date: 19 May 88 14:16:47 GMT References: <281@marob.MASA.COM> Organization: U of Maryland, Dept. of Computer Science, Coll. Pk., MD 20742 Lines: 114 In article <281@marob.MASA.COM> daveh@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@mimsy.umd.edu Path: uunet!mimsy!chris