Velocity Reviews - Computer Hardware Reviews

Velocity Reviews > Newsgroups > Programming > C Programming > Re: Ah've got them Function Pointer blues

Reply
Thread Tools

Re: Ah've got them Function Pointer blues

 
 
Keith Thompson
Guest
Posts: n/a
 
      08-29-2008
"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"
 
Reply With Quote
 
 
 
 
Default User
Guest
Posts: n/a
 
      08-29-2008
MikeC wrote:

> Keith,



Please don't top-post. Your replies belong following or interspersed
with properly trimmed quotes. See the majority of other posts in the
newsgroup, or:
<http://www.caliburn.nl/topposting.html>
 
Reply With Quote
 
 
 
 
David Thompson
Guest
Posts: n/a
 
      09-07-2008
On Fri, 29 Aug 2008 11:00:41 -0700, Keith Thompson <kst->
wrote:

> "MikeC" <> writes:

<snipped>
> 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)".
>

Yes.

> 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.
>

Yes.

> 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.
>

One exception: if you use pointer to unprototyped (unspecified but
K&R1 compatible args) function type, you can convert implicitly as
long as (just) the return type matches. But you can't necessarily use
the result to call, as noted above and detailed below.

> 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.
>

Emphatically yes, with again one exception: you must either
- call through a pointer to prototype that matches the actual routine;
- OR through a pointer to unprototyped AND the actual arguments, after
the default promotions (only), match the actual routine

The compiler can't check either of these for you, but the former is
(IMO) easier to reliably check manually thus preferable.

> 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.
> *


You can _declare_ a function using a typedef, but you can't _define_
(aka implement) it. Since many people, including me, like to have
the/any declaration(s) and definition visually the same, this
discourages using such a typedef.

> * "function_returning_void" might better have been called
> * "generic_function".
> */
> typedef int (function_returning_int) (void);
> typedef void(function_returning_void)(void);
>

<snip rest>
- formerly david.thompson1 || achar(64) || worldnet.att.net
 
Reply With Quote
 
 
 
Reply

Thread Tools

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Trackbacks are On
Pingbacks are On
Refbacks are Off


Similar Threads
Thread Thread Starter Forum Replies Last Post
Re: Ah've got them Function Pointer blues August Karlstrom C Programming 2 08-22-2008 09:36 PM
Re: Got the DRM blues? S.Heenan Computer Support 0 10-01-2005 06:47 PM
I got the Herbert Schilt, (Java 2) Package blues. Please help before I shoot the dog Rendzina Java 4 09-25-2004 01:32 PM
I've got the Vector (input parsing) blues {AGUT2}=IWIK= C++ 9 09-01-2003 07:14 AM
Got the Technical Support Blues? Austin Nights Computer Support 3 07-07-2003 10:28 PM



Advertisments
 



1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57