Casting void * to enum
Chris Mahoney (1684) 2165 posts |
I’m trying to port some existing code over to RISC OS and it’s failing when trying to cast a void * to an enum. This is a bit outside my knowledge; I try to avoid void * whenever possible so I’m not sure what exactly is going on here. Here’s a little code sample: typedef enum Pet { Cat = 0, Dog = 1, FiligreeSiberianHamster = 2 } Pet; int main(void) { void *temp = (void *)Cat; Pet mypet = (Pet)temp; return 0; } This works fine in Xcode on my Mac, and presumably also works in GCC and Microsoft’s compiler (I haven’t tested them but the docs list them as compatible). However, when using the DDE, I get “illegal cast to ‘enum Pet’”. In a pinch I could get rid of the void * completely and replace it with a true Pet object, but I’d rather not fiddle with the original code too much if I can help it. Does anyone know whether there’s a trick to getting this working? |
David Pitt (3386) 1248 posts |
Setting HTH. |
Rick Murray (539) 13840 posts |
I may be wrong here, but… You have defined an integer with a set of named values (the enum). I think that’s what is happening here, because temp is not being dereferenced, so it’s actually trying to pass back the pointer, the address of the thing, rather than the value of the thing.
Aha, “my code worked fine in the sixties and I have no truck with this newfangled nonsense” |
David Pitt (3386) 1248 posts |
Setting UNIX pcc ‘downgrades’ the Serious error to a Warning. Except that |
Chris Mahoney (1684) 2165 posts |
Thanks! I’ll read about that :)
I can certainly see where you’re coming from, but according to the docs the original code is compatible with not only GCC and Visual C++, but also whatever compilers are used for OS/2 and classic Mac OS. If it is implementation-defined then it seems that all these implementations are doing the same thing.
You should see what it looked like before I condensed it down to the minimum to make it fail!
Nope. Same error in DDE, and Xcode doesn’t like it either. Xcode suggests
Hey, it’s only from 1998 :P |
Steve Fryatt (216) 2105 posts |
You have defined an integer with a set of named values (the enum). It might be that I don’t understand your explanation, but I think you’re wrong.
The value being stored in
Again, no.
Here, that zero pointer in The problem is that C doesn’t offer a
I don’t think it does, but it’s certainly not “good” code. It’s hard to say without seeing the original code, but this looks like a classic case of trying to abuse a If I’m correct, what the library would be expecting would be something like this:
This might seem a very contrived way of doing things, and in this example it is, but it seems to be a common approach in a lot of event driven code – and in the vast majority of cases, it does exactly what is required. 1 The answer to that rhetorical question, by the way, is because when one thinks about it in more detail, it’s invariably not the correct solution to the problem. |
Andrew Rawnsley (492) 1445 posts |
Just giving Steve’s response a “+1”. Whilst I tend to avoid void* as much as possible, I encounter/deal with them quite frequently as I use RISC_OSLib. This uses void* for the purposes Steve mentioned – many event handler or alarm type functions allow you to set a trigger, and then specify a variable or structure to be passed to the handler function as a void*. Typically this might be the wimp event structure. IIRC I had a similar problem to Chris when working on LockScreen recently, but I worked around it another way. Just can’t remember the exact details, and I have a feeling it was a compiler warning not a serious error. Fuzzy Sunday-monring brain. |
Steve Fryatt (216) 2105 posts |
In my experience, it would be an application-specific pointer to some kind of internal struct. For example, in a multi-file (and hence multi-window) editor, you might have an instance of a struct for each window that’s open, holding all of its details. The Wimp event structure would be passed to the callback as a separate parameter. I don’t use RISC_OSLib (instead using my own library and OSLib), but here’s a piece of typical code1 that handles drag events within a window (there’s similar in the likes of CashBook and Locate): First, we have a function which is called to start the drag operation. This will very likely get called from the
Next, the callback function, which the event dispatcher calls when the Wimp sends the
We’re drifting from the original question, but this might provide some context as to why a 1 In my experience, at least. |
Jeffrey Lee (213) 6048 posts |
It’s complaining because you’re casting a void* to an enum. But it’s perfectly legal to cast a void* to an int, and it’s also legal to cast an int to an enum. So: Pet mypet = (Pet)(int)temp; |
Chris Mahoney (1684) 2165 posts |
Thanks, Jeffrey. That actually crossed my mind after I’d gone to bed. I haven’t tried it yet, but it sounds like it’ll do the trick! :) |
Rick Murray (539) 13840 posts |
Ah, yes. It needs the & for the address doesn’t it? At any rate, it’s coercing an integer into something that normally holds an address, then back again. The whole thing just looks like it has “implementation defined” written all over it. Ask yourself what happens on a platform where sizeof address != int (assuming enum is int, that in itself is an implementation specific issue; the compiler could choose signed short and it would still work).
Yes, it’s the “I don’t care what the data type is” option.
Whoo! Loophole abuse! ;-) |
Stuart Swales (1481) 351 posts |
Which is why we have intptr_t |
Chris Mahoney (1684) 2165 posts |
I’ve just tried it and can confirm that it works. Thanks again! |