ccastingti-dsp

Warning when type-casting between pointer and pointer-to-function


I am porting some C code to a TI DSP chip environment. I'm grappling with the C compiler.

I have a data structure that includes a pointer to a function. I have a function that initializes the data structure. Something like this:

typedef void (*PFN_FOO)(int x, int y);

struct my_struct
{
    PFN_FOO pfn;
};

init_struct(struct my_struct *p, void *pfn)
{
    p->pfn = (PFN_FOO)pfn;
}

Under Visual Studio and GCC this sort of code compiles without complaint. In fact, because the pfn argument is type void * I don't really need to even put a cast there; it would just implicitly cast without complaint.

In Code Composer Studio for the TI DSP chips, I get "warning: invalid type conversion"

My policy is to make my code compile without warnings, so I want to fix this. I have tried all sorts of casting. I discovered that the compiler is perfectly happy if I cast my void * pointer to int first, and then cast it to the correct type. Ew, yuck!

How can I do this cast without the compiler complaining? Do I really have to cast to int to shut up the compiler?

Note: I am specifically not looking for a solution to the effect of "change init_struct() to accept a PFN_FOO instead of a void *". That would work for this simplified code snippet, but would not work for the actual code, which builds a list of possibly heterogeneous stuff.


Solution

  • Standard C specifically does not support conversions between pointers to data objects and pointers to functions. GCC and Visual Studio support this as an extension.

    If you want to make your function standard-conforming (but still use the void * parameter), you could pass a pointer to a function pointer instead. This works because function pointers themselves are ordinary objects, so a pointer to a function pointer can be converted to and from void * just fine:

    init_struct(struct my_struct *p, void *pfn)
    {
        PFN_FOO *foo = pfn;
        p->pfn = *foo;
    }
    

    The caller must then create a temporary PFN_FOO object to pass a pointer to when it makes the call:

    PFN_FOO fp = &somefunc;
    /* ... */
    init_struct(p, &fp);