9

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* ?

ApprenticeHacker
  • 21,351
  • 27
  • 103
  • 153
  • May not be exactly what you need but I think some type checking is possible through GObject system – another.anon.coward Feb 01 '12 at 16:35
  • @another.anon.coward yes, I used to use that in my code, but it requires like a billion macros and practically makes my code unmaintainable. Which is the reason why, if I pick up a piece of GObject code I wrote 3 months ago, I won't be able to make head or tails of it. :( – ApprenticeHacker Feb 01 '12 at 16:40

6 Answers6

20

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.

gsamaras
  • 71,951
  • 46
  • 188
  • 305
Tony The Lion
  • 61,704
  • 67
  • 242
  • 415
4

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).

RussS
  • 16,476
  • 1
  • 34
  • 62
  • This is a cool solution, but take care: if you free the pointer, the _struct_id might still have the right values. And then, there may the case where some other object has the exact same value in its four bytes. For example, if your _struct_id is 0, you can bet that won't work because so many other objects have 0s in their first four bytes. If you go this approach, make up something crazy like 0x582fb603. Still, know that there is always the chance that something else could have those same bytes. With this kind of reliability, maybe use it in asserts or debug builds, but not otherwise. – Verdagon Mar 27 '13 at 05:17
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.

Scott Hunter
  • 48,888
  • 12
  • 60
  • 101
1

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.

Richard Chambers
  • 16,643
  • 4
  • 81
  • 106
0

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.

Lukas
  • 3,423
  • 2
  • 14
  • 26
  • 1
    Your answer doesn't look wrong, but you can improve it. Just take a look at http://stackoverflow.com/help/how-to-answer. – MERose May 11 '15 at 22:45
0

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.

Dave
  • 10,964
  • 3
  • 32
  • 54