Casting function pointers

A

Andrew Poelstra

I have a simple dictionary (right now it is implemented as a
linked list, which is more than fine for its current usage),
which accepts generic objects via void pointers, as well as
a delete function of the form void()(void *).

To make a dictionary I have:
typedef void (delete)(void *);
Dictionary *dict_new(const char *name, dict_deleter delete);

For simple objects, I might then create a dictionary and
simply give it free() as the delete function. This is a
generic container but I still only use each dictionary
for a single kind of object, so this works and makes my
dict_delete() function a lot cleaner, since it knows how
to delete all of its objects.

For dictionaries of more complex objects, though, I might
make my own delete function like:

void delete_token(Token *)

The problem is that this does not convert to

void delete_token(void *)

automatically. So either I have to cast my delete_token()
function when passing it to my dict_new() function, or
define it as taking a void* in the first place, which is
Bad because it is designed to only handle Token objects.

Neither of those are very nice solutions, IMHO. What do
you guys recommend?
 
B

Ben Bacarisse

Andrew Poelstra said:
I have a simple dictionary (right now it is implemented as a
linked list, which is more than fine for its current usage),
which accepts generic objects via void pointers, as well as
a delete function of the form void()(void *).

To make a dictionary I have:
typedef void (delete)(void *);
Dictionary *dict_new(const char *name, dict_deleter delete);

I think you intended to typedef 'dict_delete' not 'delete'. The
parentheses in the typedef are not needed. You might have had a * in
there at one time but that's not needed either and I prefer to leave
it out. For one thing it makes the typedef more useful -- you can
declare delete functions using it if it is not a pointer type:

extern dict_deleter del_token, del_list;

The delete parameter to dict_new will be converted to be of "pointer
to function type" just like an array type gets converted in a
parameter list. I don't like to rely on that because it is a little
know part of the language -- instead I add the * at that point.
For simple objects, I might then create a dictionary and
simply give it free() as the delete function. This is a
generic container but I still only use each dictionary
for a single kind of object, so this works and makes my
dict_delete() function a lot cleaner, since it knows how
to delete all of its objects.

For dictionaries of more complex objects, though, I might
make my own delete function like:

void delete_token(Token *)

The problem is that this does not convert to

void delete_token(void *)

automatically. So either I have to cast my delete_token()
function when passing it to my dict_new() function, or
define it as taking a void* in the first place, which is
Bad because it is designed to only handle Token objects.

Neither of those are very nice solutions, IMHO. What do
you guys recommend?

I don't think you can choose if you want to stick to the letter of the
standard. A function must be called through a pointer of the correct
type and since the pointer won't be converted by the dictionary code,
you have to make the deleter take a void *.

This is a summary of whole bunch of clauses all relating to calling
functions. Like any summary it misses a lot of details but it
captures the essence if you are using modern functions with prototypes
and don't have and ... in the parameter list.
 
E

Eric Sosman

I have a simple dictionary (right now it is implemented as a
linked list, which is more than fine for its current usage),
which accepts generic objects via void pointers, as well as
a delete function of the form void()(void *).

To make a dictionary I have:
typedef void (delete)(void *);
Dictionary *dict_new(const char *name, dict_deleter delete);

ITYM `delete dict_deleter', or else you typo'ed the typedef.
For simple objects, I might then create a dictionary and
simply give it free() as the delete function. This is a
generic container but I still only use each dictionary
for a single kind of object, so this works and makes my
dict_delete() function a lot cleaner, since it knows how
to delete all of its objects.

For dictionaries of more complex objects, though, I might
make my own delete function like:

void delete_token(Token *)

The problem is that this does not convert to

void delete_token(void *)

automatically. So either I have to cast my delete_token()
function when passing it to my dict_new() function, or
define it as taking a void* in the first place, which is
Bad because it is designed to only handle Token objects.

Neither of those are very nice solutions, IMHO. What do
you guys recommend?

The latter, because the former is not guaranteed to work
(although it frequently does). This is the same situation
faced by qsort() and bsearch(), and the same solution applies.
Write your deleter like

void delete_token(void *pp) {
Token *p = pp;
... work with p ...
}

The disadvantage is that this delete_token() will accept
a pointer to pretty much anything, not just a Token*, so if
you call it with a Broken* by accident the compiler won't raise
a fuss. I'm afraid That's The Way It Is in a language that
doesn't have "generic types."
 
A

Andrew Poelstra

ITYM `delete dict_deleter', or else you typo'ed the typedef.

Yes, I did typo it. (And thanks Keith for pointing out that
the parens were not necessary.)
The latter, because the former is not guaranteed to work
(although it frequently does). This is the same situation
faced by qsort() and bsearch(), and the same solution applies.
Write your deleter like

void delete_token(void *pp) {
Token *p = pp;
... work with p ...
}

Okay, this is what I've got now, thanks.
The disadvantage is that this delete_token() will accept
a pointer to pretty much anything, not just a Token*, so if
you call it with a Broken* by accident the compiler won't raise
a fuss. I'm afraid That's The Way It Is in a language that
doesn't have "generic types."

Okay, so it's not just me. :)
 
K

Keith Thompson

Andrew Poelstra said:
Yes, I did typo it. (And thanks Keith for pointing out that
the parens were not necessary.)

That was Ben Bacarisse, not me.

[snip]
 
I

ImpalerCore

I have a simple dictionary (right now it is implemented as a
linked list, which is more than fine for its current usage),
which accepts generic objects via void pointers, as well as
a delete function of the form void()(void *).

To make a dictionary I have:
  typedef void (delete)(void *);
  Dictionary *dict_new(const char *name, dict_deleter delete);

For simple objects, I might then create a dictionary and
simply give it free() as the delete function. This is a
generic container but I still only use each dictionary
for a single kind of object, so this works and makes my
dict_delete() function a lot cleaner, since it knows how
to delete all of its objects.

For dictionaries of more complex objects, though, I might
make my own delete function like:

  void delete_token(Token *)

The problem is that this does not convert to

  void delete_token(void *)

automatically. So either I have to cast my delete_token()
function when passing it to my dict_new() function, or
define it as taking a void* in the first place, which is
Bad because it is designed to only handle Token objects.

Neither of those are very nice solutions, IMHO. What do
you guys recommend?

The C FAQ 13.9 recommends making a wrapper function that explicitly
casts the pointer to the correct type.

i.e.

void my_string_free( my_string_t* mstr );
void my_string_vfree( void* p )
{
my_string_t* mstr = (my_string_t*)p;
my_string_free( mstr );
}

my_dictionary_free( dict, my_string_vfree );
 
C

chrisbazley

I think you intended to typedef 'dict_delete' not 'delete'.  The
parentheses in the typedef are not needed.  You might have had a * in

I have been blind to this (parentheses not required in function type
definition) for a long time. I'm glad that I read this newsgroup where
my thoughtless habits are challenged. :)
there at one time but that's not needed either and I prefer to leave
it out.  For one thing it makes the typedef more useful -- you can
declare delete functions using it if it is not a pointer type:

  extern dict_deleter del_token, del_list;

My previous employer's coding standard forbade hiding pointers behind
typedefs; a rule which was generally adhered to for struct and union
types but widely flouted for function types. I have used your form of
function declaration in my own code. I only wish I had thought of it
when arguing the applicability of the manifest pointer rule to
functions!

Cheers,
 
C

chrisbazley

On Mar 11, 3:52 pm, Andrew Poelstra <[email protected]>
wrote: [snip]
For dictionaries of more complex objects, though, I might
make my own delete function like:
void delete_token(Token *)
The problem is that this does not convert to
void delete_token(void *)
automatically. So either I have to cast my delete_token()
function when passing it to my dict_new() function, or
define it as taking a void* in the first place, which is
Bad because it is designed to only handle Token objects.
Neither of those are very nice solutions, IMHO. What do
you guys recommend?

The C FAQ 13.9 recommends making a wrapper function that explicitly
casts the pointer to the correct type.

i.e.

void my_string_free( my_string_t* mstr );
void my_string_vfree( void* p )
{
my_string_t* mstr = (my_string_t*)p;
my_string_free( mstr );

}

my_dictionary_free( dict, my_string_vfree );

Surely this is slower and inflates the code size - especially if the
compiler embeds function names and sets up a stack frame in the
wrapper function. What advantage does it have over simply using the
(strongly-typed) 'mstr' pointer within the my_string_vfree() function?

Also, I can't find the recommendation that you allude to in
http://c-faq.com/lib/qsort2.html

Cheers,
 
I

ImpalerCore

On Mar 11, 3:52 pm, Andrew Poelstra <[email protected]>
wrote: [snip]
For dictionaries of more complex objects, though, I might
make my own delete function like:
  void delete_token(Token *)
The problem is that this does not convert to
  void delete_token(void *)
automatically. So either I have to cast my delete_token()
function when passing it to my dict_new() function, or
define it as taking a void* in the first place, which is
Bad because it is designed to only handle Token objects.
Neither of those are very nice solutions, IMHO. What do
you guys recommend?
The C FAQ 13.9 recommends making a wrapper function that explicitly
casts the pointer to the correct type.

void my_string_free( my_string_t* mstr );
void my_string_vfree( void* p )
{
  my_string_t* mstr = (my_string_t*)p;
  my_string_free( mstr );

my_dictionary_free( dict, my_string_vfree );

Surely this is slower and inflates the code size - especially if the
compiler embeds function names and sets up a stack frame in the
wrapper function. What advantage does it have over simply using the
(strongly-typed) 'mstr' pointer within the my_string_vfree() function?

The C-FAQ recommends against casting because the result of the cast is
not guaranteed. The compiler may implement the "right" behavior, but
you do so at your own risk. This is assuming that you are intending
the dictionary to use the generic 'void (*)( void* )' as the free
interface function pointer type.

The C-FAQ didn't recommend the option that I gave specifically, it was
my recommendation, based on my personal experience designing
containers. There are a couple other options that I considered.

1. Just create a my_string_free with a void* parameter.

void my_string_free( void* mstr );

The risk is that if you pass in a pointer to a different type, bad
things can happen and the compiler will likely not warn you about it.
Not every string free will be a string in a container, so I want the
compiler to catch those errors.

char* str = my_strdup( "Hello" );
my_string_free( str ); /* Oops. Will the compiler recognize the
error? */

And yes, I was bitten by that kind of bug.

2. Create two separate functions, with nearly identical code.

void my_string_free( my_string_t* mstr )
{
/* free code */
}

void my_string_vfree( void* p )
{
my_string_t* mstr = (my_string_t*)p;
/* free code */
}

In this scenario, you duplicate the code trading the performance
penalty of nesting a function within another with the cost of
maintaining two nearly identical pieces of code.

3. The scenario I suggested used a nested call to avoid the
maintenance cost since it is likely that the overall gain in
performance is not worth having to maintain two separate copies of the
code. In the case that the user really wants to avoid the penalty,
and if it really results in measurable gains, the user can write his
own wrapper and use that.

void my_string_fast_vfree( void* p )
{
my_string_t* mstr = (my_string_t*)p;
/* free code */
}

I chose to use the above wrapper simply because of the reduced code
maintenance cost, and the user is able to write their own version
without the wrapper for performance *if* need be. It's just my
opinion, so take it as such. If you find yourself creating and
destroying lots of dictionaries and because of that, lots of strings,
and because of that, the performance is unacceptable then use the
wrapper and see if it buys you anything.

Best regards,
John D.
 
C

chrisbazley

On Mar 15, 8:30 pm, (e-mail address removed) wrote: [snip]
Surely this is slower and inflates the code size - especially if the
compiler embeds function names and sets up a stack frame in the
wrapper function. What advantage does it have over simply using the
(strongly-typed) 'mstr' pointer within the my_string_vfree() function?

The C-FAQ recommends against casting because the result of the cast is
not guaranteed.  The compiler may implement the "right" behavior, but
you do so at your own risk.  This is assuming that you are intending
the dictionary to use the generic 'void (*)( void* )' as the free
interface function pointer type.

Yes, I understood that point and found it interesting, because I
hadn't previously considered the validity of casting function
pointers.
The C-FAQ didn't recommend the option that I gave specifically, it was
my recommendation, based on my personal experience designing
containers.  There are a couple other options that I considered.

Okay, I went and looked at the FAQ and thought maybe I had missed it
or I was looking in the wrong place.
1.  Just create a my_string_free with a void* parameter.

void my_string_free( void* mstr );

The risk is that if you pass in a pointer to a different type, bad
things can happen and the compiler will likely not warn you about it.

As Eric said, 'That's The Way It Is in a language that doesn't have
"generic types."'.
Not every string free will be a string in a container, so I want the
compiler to catch those errors.

I agree, type-safety is very important.

[snip]
2.  Create two separate functions, with nearly identical code. [snip]
In this scenario, you duplicate the code trading the performance
penalty of nesting a function within another with the cost of
maintaining two nearly identical pieces of code.

I would never countenance that option. :)
3.  The scenario I suggested used a nested call to avoid the
maintenance cost since it is likely that the overall gain in
performance is not worth having to maintain two separate copies of the
code.

I would probably grimace and do likewise, but ONLY if the destructor
were likely to be called in some other circumstance where type-safety
could be enforced. I assumed that it had been written for the specific
purpose of being called through a weakly-typed function pointer (which
is why I couldn't see any point in your wrapper function).

Cheers,
 
I

ImpalerCore

On Mar 15, 8:30 pm, (e-mail address removed) wrote: [snip]
Surely this is slower and inflates the code size - especially if the
compiler embeds function names and sets up a stack frame in the
wrapper function. What advantage does it have over simply using the
(strongly-typed) 'mstr' pointer within the my_string_vfree() function?
The C-FAQ recommends against casting because the result of the cast is
not guaranteed.  The compiler may implement the "right" behavior, but
you do so at your own risk.  This is assuming that you are intending
the dictionary to use the generic 'void (*)( void* )' as the free
interface function pointer type.

Yes, I understood that point and found it interesting, because I
hadn't previously considered the validity of casting function
pointers.
The C-FAQ didn't recommend the option that I gave specifically, it was
my recommendation, based on my personal experience designing
containers.  There are a couple other options that I considered.

Okay, I went and looked at the FAQ and thought maybe I had missed it
or I was looking in the wrong place.
1.  Just create a my_string_free with a void* parameter.
void my_string_free( void* mstr );
The risk is that if you pass in a pointer to a different type, bad
things can happen and the compiler will likely not warn you about it.

As Eric said, 'That's The Way It Is in a language that doesn't have
"generic types."'.
Not every string free will be a string in a container, so I want the
compiler to catch those errors.

I agree, type-safety is very important.

[snip]
2.  Create two separate functions, with nearly identical code. [snip]
In this scenario, you duplicate the code trading the performance
penalty of nesting a function within another with the cost of
maintaining two nearly identical pieces of code.

I would never countenance that option. :)
3.  The scenario I suggested used a nested call to avoid the
maintenance cost since it is likely that the overall gain in
performance is not worth having to maintain two separate copies of the
code.

I would probably grimace and do likewise, but ONLY if the destructor
were likely to be called in some other circumstance where type-safety
could be enforced. I assumed that it had been written for the specific
purpose of being called through a weakly-typed function pointer (which
is why I couldn't see any point in your wrapper function).

I had originally just used a function pointer cast till I stumbled
across that C FAQ myself. I don't particularly like the solution, but
it's the one that plays the nicest imo.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,770
Messages
2,569,584
Members
45,075
Latest member
MakersCBDBloodSupport

Latest Threads

Top