daveh@marob.MASA.COM (Dave Hammond) (05/19/88)
Given a list of varying typed functions, their names and addresses: struct funcs { char *name; unsigned (*func)(); } char *foo(); struct funcs f = { "foo", (char *)foo }; And a routine which is passed a function name in order to lookup and return its associated address: unsigned *lookup_func(name) char *name; { ... return( (unsigned *) f->func ); } How does one declare the lookup function, the return address variable and call the returned function, while properly casting the function return value? 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); } Yes? No? Gonna blow up on me at some point ? Dave Hammond DSI Communications, Inc. -------------------------------- UUCP: ...!marob!daveh VOICE: (516)872-3535 USMAIL: 333 W. Merrick Rd. Valley Stream, NY 11580 --------------------------------
chris@mimsy.UUCP (Chris Torek) (05/19/88)
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
djones@megatest.UUCP (Dave Jones) (05/20/88)
in article <281@marob.MASA.COM>, daveh@marob.MASA.COM (Dave Hammond) says: > > > Given a list of varying typed functions, their names and addresses: > > struct funcs { > char *name; > unsigned (*func)(); > } > char *foo(); > struct funcs f = { "foo", (char *)foo }; ... typedef unsigned (*func_ptr)(); struct funcs { char* name; func_ptr func; } func_table; func_ptr func_lookup() { ... whatever ... } { func_ptr proc; char* func_name = ... whatever ...; unsigned result; if((proc = func_lookup(func_name)) != (func_ptr)0) result = (*proc)(); else fprintf(stderr, "Shucks.\n"); }
walter@hpcllz2.HP.COM (Walter Murray) (05/21/88)
Dave Hammond writes: >Given a list of varying typed functions, 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? >I'm doing it like so: [all examples deleted] >Yes? No? Gonna blow up on me at some point ? Dave, if I understand you right, when you call lookup_func("foo"), you know what type foo() is going to return, and you just need to look up its address. If that's the case, I think the following is what you want. It's close to what you had, and lint likes it. Other things will work, but I think the following has the virtue of being strictly conforming per the dpANS. #include <stdio.h> #include <string.h> struct funcs {char *name; void (*func)();}; char *foo() {return "It worked!";}; struct funcs f = {"foo",(void(*)())foo}; void (*lookup_func(name))() char *name; { if (!strcmp (name, f.name)) return f.func; else return 0; } void (*func)(); char *retp; main () { if ((func = lookup_func ("foo")) != 0) if ((retp = ((char*(*)())func)()) != 0) (void) printf ("retp = %s\n",retp); return 0; } Walter Murray All opinions expressed are my own.
chris@trantor.umd.edu (Chris Torek) (05/23/88)
In article <7330003@hpcllz2.HP.COM> walter@hpcllz2.HP.COM (Walter Murray) writes: >... but I think the following has the virtue of being strictly >conforming per the dpANS. ... > >struct funcs {char *name; void (*func)();}; >char *foo() {return "It worked!";}; >struct funcs f = {"foo",(void(*)())foo}; This is not strictly conforming, because the standard does not say whether objects of type `void (*)()' are in any way compatible with objects of type `char *(*)()'. (It says very little about pointers to functions, no matter what the return type of the function. It does not even say whether `void *' and `t (*)()' are compatible.) Since, however, `char *' and `void *' are `the same', using a base type of `void *(*)()' should work. Most likely, pointers to any function, no matter what the return type, will have the same format, but it would be nice to have some guarantees. -- In-Real-Life: Chris Torek, Univ of MD Computer Science, +1 301 454 7163 Domain: chris@mimsy.umd.edu Path: ...!uunet!mimsy!chris
walter@hpcllz2.HP.COM (Walter Murray) (05/23/88)
chris@trantor.umd.edu (Chris Torek) writes: >In article <7330003@hpcllz2.HP.COM> walter@hpcllz2.HP.COM (Walter Murray) >writes: >>... but I think the following has the virtue of being strictly >>conforming per the dpANS. ... >> >>struct funcs {char *name; void (*func)();}; >>char *foo() {return "It worked!";}; >>struct funcs f = {"foo",(void(*)())foo}; >This is not strictly conforming, because the standard does not say >whether objects of type `void (*)()' are in any way compatible with >objects of type `char *(*)()'. (It says very little about pointers >to functions, no matter what the return type of the function....) > >Most likely, pointers to any function, no matter what the return >type, will have the same format, but it would be nice to have some >guarantees. I was relying on the following statement from page 47 of the January draft: "A pointer to a function of one type may be converted to a pointer to a function of another type and back again; the result shall compare equal to the original pointer." That sounds to me like a guarantee. Did I read too much into it? Walter Murray All opinions expressed are my own.
chris@mimsy.UUCP (Chris Torek) (05/25/88)
>chris@trantor.umd.edu (me, using trantor while the broadband network was out), write: >>This is not strictly conforming, because the standard does not say >>whether objects of type `void (*)()' are in any way compatible with >>objects of type `char *(*)()'. ... In article <7330004@hpcllz2.HP.COM> walter@hpcllz2.HP.COM (Walter Murray) writes: >... page 47 of the January draft: "A pointer to a function of one >type may be converted to a pointer to a function of another type and >back again; the result shall compare equal to the original pointer." Oops. You are right; I missed this paragraph. (Though I wonder whether some implementor might construe this to mean that the result need only *compare equal* but not necessarily be *useful*. But that would be stupid.) -- In-Real-Life: Chris Torek, Univ of MD Comp Sci Dept (+1 301 454 7163) Domain: chris@mimsy.umd.edu Path: uunet!mimsy!chris