ju*********@yahoo.com wrote:
Hi everyone
I am interested in having multiple functions with different prototypes
and deciding, by setting a pointer, which of them to use later in the
program.
Eg:
int f1(void);
char* f2(int);
/* ... many more of these to choose from */
/* ? correct declaration of generic_ptr ? */
if (/*...*/)
generic_ptr = f1;
else
generic_ptr = f2;
This is not possible, but you can do something like
void (*generic_ptr)();
if (/*...*/)
generic_ptr = (void(*)()) f1;
else
generic_ptr = (void(*)()) f2;
Although I usually consider typedefs for pointer types to be
a Bad Thing, this is one of the exceptions where it seems to
me the readability can be improved a lot:
typedef void (*FuncPtr)();
FuncPtr generic_ptr;
if (/*...*/)
generic_ptr = (FuncPtr)f1;
else
generic_ptr = (FuncPtr)f2;
generic_ptr(/* using correct args */)
You can *almost* do this, but only if all of your functions
obey some rather strange restrictions:
- All of f1, f2, ... and generic_ptr must return the same
type, or all must be void
AND
- None of f1, f2, ... and generic_ptr can be a variadic
function, or all must be variadic and have the same number
and types of fixed arguments
AND
- If the argument types are omitted (as above), then all the
arguments to all of f1, f2, ... must be non-promotable, or
all of f1, f2, ... must be defined with the obsolescent
"K&R" syntax.
The problem is that the type of the pointer with which you
call a function must agree with the actual type of the function
that is called. The strange restrictions listed above allow you
to skirt the agreement rule just a little bit -- but there's
still no way you can use the same pointer expression to call a
function returning int *and* a function returning double, for
example.
An alternative is to cast at the point of call, which again
is clarified by the use of some typedefs:
typedef int (*IntOfVoid)(void);
typedef char* (*StrOfInt)(int);
if (/*...*/)
i = ((IntOfVoid)generic_ptr)();
else
s = ((StrOfInt)generic_ptr)(42);
How should I define generic_ptr? Is (void*) ok? It seems to work on my
machine, but I would like to know if this is standard/portable.
See above. No. Happenstance, and it's not.
If the functions f1, f2, ... really bear no resemblance to
each other you're pretty much doomed to casting -- but in such a
case it's hard to see why you'd want to use a single "generic"
pointer in the first place. If they are related in some way but
differ in details, it may be better to use wrapper functions.
For example, suppose all the functions return int values, all
take two int arguments, and some also take a third string argument.
You could do something like
int f1(int, int, char*);
int f2(int, int, char*);
int f3(int, int); /* only two arguments */
int wrapf3(int x, int y, char* unused) {
return f3(x, y);
}
typedef int (*FuncPtr)(int, int, char*);
FuncPtr fptr;
if (/*...*/)
fptr = f1;
else if (/*...*/)
fptr = f2;
else
fptr = wrapf3; /* note indirection */
printf ("%d\n", fptr(42, 29, "Zaphod Rulez!"));
This technique may appear limiting at first glance, but when
you start applying it to actual "families" of "broadly similar"
functions it works quite well.
--
Er*********@sun.com