How to check if a void* pointer can be safely cast to something else?

若如初见. 提交于 2019-12-19 09:09:49

问题


Let's say I have this function, which is part of some gui toolkit:

typedef struct _My_Struct My_Struct;
/* struct ... */

void paint_handler( void* data )
{
   if ( IS_MY_STRUCT(data) ) /* <-- can I do something like this? */
   {
      My_Struct* str = (My_Struct*) data;
   }
}

/* in main() */
My_Struct s;
signal_connect( SIGNAL_PAINT, &paint_handler, (void*) &s ); /* sent s as a void* */

Since the paint_handler will also be called by the GUI toolkit's main loop with other arguments, I cannot always be sure that the parameter I am receiving will always be a pointer to s.

Can I do something like IS_MY_STRUCT in the paint_handler function to check that the parameter I am receiving can be safely cast back to My_Struct* ?


回答1:


Your void pointer looses all its type information, so by that alone, you cannot check if it can be cast safely. It's up to the programmer to know if a void* can be cast safely to a type.




回答2:


Unfortunately there is no function to check what the pointer was before it appears in that context (void).

The one solution I can think of is if you place an int _struct_id as the first member of all of your structs. This id member can then be safely checked regardless of the type but this will fail if you pass pointers that don't implement this member (or int, char, ... pointers).




回答3:


The best you could do would be to look at what data points to to see if it has telltale signs of being what you want, although a) it wouldn't be anywhere close to a guarantee and b) might be dangerous, as you don't know how big the thing data actually points to is. I suppose it isn't any more dangerous than just casting it and using it, but (as has been suggested) a redesign would be better.




回答4:


There really isn't in c. void pointers are typeless, and should only ever be casted when you truly know what they point to.

Perhaps you should instead reconsider your design; rewrite your code so that no inspection is necessary. This is the same reason google disallows RTTI in its style guide.




回答5:


If you are creating the type that is being used, you could include as part of the type some kind of identifying information that would help you rule out some void pointers as not being of the type you are looking for. While you would run the chance that some random area of memory would contain the same data or signature as what you are looking for, at least you would know when something was not the type you were looking for.

This approach would require that the struct was initialized in such a way that the signature members, used to determine if the memory area is not valid, is initialized to the signature value.

An example:

typedef struct {
    ULONG  ulSignature1;
    //  .. data elements that you want to have
    ULONG  ulSignature2;
} MySignedStruct;
#define MYSIGNEDSTRUCT_01  0x1F2E3D4C
#define MYSIGNEDSTRUCT_02  0xF1E2D3C4

#define IS_MY_STRUCT(sAdr)  ( (((MySignedStruct *)sAdr)->ulSignature1 == MYSIGNEDSTRUCT_01  ) && (((MySignedStruct *)sAdr)->ulSignature1 == MYSIGNEDSTRUCT_02))

This is kind of a rough approach however it can help. Naturally using a macro like IS_MY_STRUCT() where the argument is used twice can be problematic if the argument has a side effect so you would have to be careful of something like IS_MY_STRUCT(xStruct++) where xStruct is a pointer to a MySignedStruct.




回答6:


I know the question is 3 years old but here I go, How about using a simple global enum to distinguish where the function is called from. then you can switch between what type to cast the void pointer to.



来源:https://stackoverflow.com/questions/9099384/how-to-check-if-a-void-pointer-can-be-safely-cast-to-something-else

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!