"MikeC" <> writes:
[...]
> To bring my question down to the simplest form, if I have a function
>
> int return_42(void)
> { return 42;
> }
>
> then I declare a function pointer...
>
> int main()
> { void (*fpv)();
> int i;
>
> fpv = ????
> i = <cast>fpv;
> }
>
> My question is this - how do I make fpv point to the function return_42, and
> how do I induce it to assign the return value to i?
Use prototypes consistently. Empty parentheses in a function
declaration mean that the function has an unspecified number and
type(s) of parameters. <OT>It's different in C++.</OT> To declare
that a function has no parameters, use "(void)".
You can make fpv (a pointer to function returning void) point to
return_42 (a function returning int), but you cannot make an indirect
call using the value of fpv, because the types don't match. The
behavior of such a call is undefined.
Things to remember:
You can convert between any pointer-to-function type and any other
pointer-to-function type. Such conversions always require a cast;
they're never done implicitly.
For object pointers, void* is a generic pointer type. For function
pointers, since they're *all* freely convertible, you can use any
function pointer type you like as a generic type. It's probably best
to use the simplest such type, ``void (*)(void)''.
When you call a function via a pointer-to-function, you must use a
pointer-to-function whose target type matches the type of the actual
function you're calling. The compiler won't check this for you, so
it's easy to get this wrong and invoke undefined behavior. For
example, if you call a function that returns an int via a pointer to a
function returning void, the code for the call will assume that the
function returns no value. Arbitrarily bad things can happen. If
you're particularly unlucky, it will appear to work, making it harder
to detect the bug.
Here's an example of the right way to do it. I use typedefs to make
the code easier.
#include <stdio.h>
/*
* Note that we can't use these typedefs directly; you
* can't declare a function object. But we can declare
* objects that are pointers to functions. I could
* reasonably have declared typedefs for the pointer types,
* but I dislike hiding pointers behind typedefs.
*
* "function_returning_void" might better have been called
* "generic_function".
*/
typedef int (function_returning_int) (void);
typedef void(function_returning_void)(void);
int return_42(void)
{
return 42;
}
int main(void)
{
/*
* Declare fpv as a pointer to a function_returning_void.
*/
function_returning_void *fpv;
int i;
/*
* return_42, as an expression, is a pointer to a
* function_returning_int. fpv is of type pointer to
* function_returning_void. Since there's no implicit
* conversion, we need to use a cast.
*/
fpv = (function_returning_void *)return_42;
/*
* Now we can't make a function call using the value
* of fpv directly, because the types don't match.
* The behavior of such a call would be undefined.
* So we take the value of fpv, which is a pointer to
* function_returning_void, and convert it *back* to a
* pointer to function_returning_int. We can now call
* return_42() indirectly through this pointer value,
* which is now of the correct type.
*/
i = ((function_returning_int *)fpv)();
/*
* Output: "i = 42"
*/
printf("i = %d\n", i);
return 0;
}
--
Keith Thompson (The_Other_Keith)
kst- <http://www.ghoti.net/~kst>
Nokia
"We must do something. This is something. Therefore, we must do this."
-- Antony Jay and Jonathan Lynn, "Yes Minister"