7

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.

steveha
  • 74,789
  • 21
  • 92
  • 117
  • Wouldn't it be simpler to just have correct type agreement and make pfn type PFN_FOO? Another point - you ought to give init_struct() an explicit type; that does not compile without warnings in VC++2008 even using C compilation. – Clifford Oct 12 '09 at 21:39
  • @Clifford, my actual code always has explicit types on functions; I write my code to compile without any warnings and I am careful with types. The problem I am solving is to make a function that initializes a data structure that can have heterogeneous stuff in it, and I want a single init function, not one init function per possible type of data stored inside it. – steveha Oct 12 '09 at 22:01

2 Answers2

13

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);
caf
  • 233,326
  • 40
  • 323
  • 462
  • 1
    Wow, I was thinking this was a TI C thing, but you are telling me it is a C standard thing. That's very helpful. – steveha Oct 12 '09 at 21:56
  • 1
    Okay, I rewrote my function so that instead of taking a `void *`, it takes a `PFN`, defined as so: `typedef void (*PFN)();` And now the code compiles without warning. It's enough that it starts out as some kind of pointer to function, before being cast into a specific PFN type. Thank you! Answer accepted and +1. – steveha Oct 12 '09 at 21:58
  • That's right, you can freely convert between different function pointer types. – caf Oct 12 '09 at 23:34
3

Shouldn't you write?

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

See this tutorial.

dirkgently
  • 108,024
  • 16
  • 131
  • 187
  • Er, yes. I have it correct in the actual code, and I'll change my stupid example code to be correct. Now, do you have any advice on the actual question? – steveha Oct 12 '09 at 20:48
  • Just to clarify: you might have suspected that the problem was my code not declaring the PFN_FOO type correctly. That is not the problem, and the code actually works quite well, but the TI DSP C compiler is giving me warnings on it. – steveha Oct 12 '09 at 20:52
  • Are you compiling as C or C++? – dirkgently Oct 12 '09 at 21:35
  • If this were C++, I wouldn't have to mess around with this stuff; I could use virtual pointers and C++ would do all the work for me. – steveha Oct 12 '09 at 22:37