Generic Function Pointers In C And Void *

Subscribe To Our Feed | Follow Us On Twitter | Get Updates on Email

Many times people ask me about what keyword \ type they should use to declare a generic function pointer in C, or worse still, they don’t ask and steam ahead using “void *”. Well, C does not have a generic function pointer type but it does have a generic function pointer. We’ll see why void * cannot be used to denote generic function pointers and so how we can declare them, but first a brief word on why would someone need a generic function pointer in the first place.

Why do we need Generic Function Pointers?

Well, let’s explain this with the help of a slightly advanced example of a module M1 that supplies information to a lot of other modules M2, M3, M4…Mn. M1 provides this information to modules Mn through callbacks but all these modules need different kind of information and different prototypes for their callback functions. These modules register with M1, using an API, say M1_register(Mn_callback_ptr). Now, either we could have a separate registration API for each “type/class” of subscriber Modules depending on what kind of callback they are giving, or we can have a generic function pointer, to which they typecast their actual callback to and then call the registration API. M1, on the other hand, typecasts this callback pointer to its original form while calling callbacks appropriately.

Why can’t we use void* for a Generic Function Pointer?

This is because a void* is a pointer to a generic “data” type. A void * is used to denote pointers to objects and in some systems, pointers to functions can be larger than pointers to objects. So, if you convert amongst them, you’ll lose information and hence, the situation would be undefined and implementation dependent. Most compilers won’t even warn you if you convert between them but some might error out, if you try to call such a void * to function pointer converted. But even they might fail to alert you, if you take care of typecasting the call perfectly (Enclose in parentheses before function call brackets). And then, one fine day, you’ll try to compile and run your program on one of the aforementioned systems, and then keep on wondering why your program segfaults.

Note: C++ does allow this “conditionally” which means that such a conversion is allowed but a compiler is not bound to implement this feature, which again makes its usage circumspect.

So, how exactly do we declare a Generic Function Pointer?

Well, just like any other function pointer. You can use any function pointer as a generic function pointer, however you need to typecast it properly before calling the actual function it points to. e.g., you can try out the following program as an example.

#include <stdio.h>
/* This is our generic function pointer */
typedef void (*fp)(void);
int func1(int a)
{
   printf(&quot;Inside Func 1. Received %d\n&quot;, a);
   return 2;
}
 
char func2(char b)
{
   printf(&quot;Inside Func 2. Received %c\n&quot;, b);
   return 'b';
}
 
int main()
{
   fp ptr1;
   int temp1;
   char temp2;
   /* Typecast the original function to generic function pointer before assigining */
   ptr1 = (fp) func1;
   /* Typecast back to original function type before calling. The syntax to do this typecasting is quite convoluted though, as you can see. */
   temp1 = ((int (*)(int)) ptr1)(1);
   ptr1 = (fp) func2;
   temp2 = ((char (*)(char))ptr1)('a');
   printf(&quot;Inside Main. Received %d %c\n&quot;, temp1, temp2);
   return 0;
}

End Note: How can I use the same variable for object / data and function pointers inter-changeably?

Simple, use a union of a void * and the function pointer (like we described above) and you need not worry about the size because the compiler will automatically choose the largest size for this union which can hold a function pointer.

Let us know if you found this article helpful or think we missed something. Also, send in your queries on anything related to C / C++, Secure programming, etc that you’d like us to answer.

© Safer Code | Generic Function Pointers In C And Void *

Liked this post? Get FREE Updates
Subscribe to RSS feed

Or
Enter Your E-mail ID below

Share and Enjoy:
  • Digg
  • del.icio.us
  • Facebook
  • StumbleUpon
  • Reddit
  • Print this article!

Related posts

Tags: , , , , ,

6 Comments

  • Vikas says:

    Hmm….I am still not sure how would M1 get to know the version of the callback to call. I mean suppose M2 passes a callback of type (int (*)(int)) and M3 passes (char (*)(char)). Both of then cast it to (void (*)(void)) while passing to M1 but M1 has no idea which version to cast it back to??? I think the registration API would at least need something like enum { (int (*)(int)), (char (*)(char))} reg_fn_callback_type; to be passed to it???

    Moreover, isn’t FAR* good enough with a right-type-enum? I mean is that a compiler dependent type? Or is it that my dream which ended with TurboC++ :) ?

  • @Vikas: Yes, M1 needs to know the exact prototype while caling it, hence it needs to know it either statically or through some macro mumbo-jumbo (can’t do it through enums). The advantage here is that the registration api remains constant, and the actual calling part, which is anyways dependent on the type of module, will typecast it appropriately before calling. (Think of a layer that interacts with various drivers to collect events from them and provide different notifications to upper layers)
    About far, it has many issues, as in the function being called may not actually be far, using this will unnecessarily complicate things for the compiler and your programs will slow down. There won’t be any type checking as well. And most importantly, far is non-standard, so you can’t even rely on it while moving from one compiler/platform to another.

  • guruwars says:

    In C or just a simple unit type case, union is a good choice, but in C++, with complex type would not be preferred because of wasting of memory. At big size structure, how about using inheritance, i think.

  • Sean says:

    Another way to get a function pointer from a void * is to cast your function pointer to a void ** and dereference it. Lame example below.

    int call_fp_from_vp(void *vp)
    {
    int (*fp)(int);

    *(void **)(&fp) = vp;

    return fp(0);
    }

  • @Sean: I don’t think that would be portable because data and function pointer sizes might differ on different architectures and might lead to truncation of the address and information once lost in such a case (by using void * for a function pointer) can not be recovered by the trick that you mentioned.

  • Nonce says:

    You didn’t actually mention what systems have a difference sized void and function pointer in C. What systems are these? OS/400? VAX/VMS? I’ve never heard of such a system.

Leave a Reply