The whole code is written in ANSI C, and it should remain so.
I have a callback defined like so:
typedef enum {
Event_One,
Event_Two,
Event_State
} EventEnum;
typedef void (*callback)(EventEnum event, void* data);
The callback recipient interprets data depending on the event value. This is the contract between the components. Sometimes it is a pointer to the structure, sometimes it might be a string, other cases might be other data. I am defining an additional event and setting up a new “contract” that data is an enumeration. Like so:
typedef enum {
State_Initial = 0,
State_Running,
State_Final
} StateEnum;
Then somewhere in the code I have a callback function, which is doing this
void ProcessEvent (EventEnum event, void* data)
{
if (event == Event_State)
{
StateEnum state = (StateEnum)data; /* <<<<<<<<<<< */
switch (state) {
case State_Initial:
<...>
break;
case State_Running:
<...>
break;
case State_Final:
<...>
break;
}
}
}
The callback above is called like so:
{
callback infoCallback = ProcessEvent; /* This is only for example,
done during initialization */
<...>
StateEnum someState = State_Running;
<...>
infoCallback(Event_State, (void*)someState); /* <<<<<<<<<<<<<<<<<<< */
}
Is there anything fundamentally wrong with typecasting void* to StateEnum and vice versa? What are the possible gotchas in this way? Any thoughts on testability and maintainability?
EDIT : The code compiles, links and runs OK right now. I want to know why this should not be done and if there are any real reasons why the code must be changed.
Only pointers to objects (i.e., not functions) can be converted to
void *and back. You can’t convert a non-pointer tovoid *and back. So, change your call to:And your function to:
From the standard (6.3.2.3):
So, what you are doing is implementation-defined. If your implementation defines it to be OK to convert
intto a pointer and back, then the code will work. In general, it is not portable. For more details, see this thread on comp.lang.c.C99 additionally defines types
intptr_tanduintptr_t, which are integral types, and it is guaranteed to convert avoid *to them and back.