Casting a void * into a 32-bit struct

Discussion in 'C Programming' started by Luc Le Blanc, Nov 11, 2003.

  1. Luc Le Blanc

    Luc Le Blanc Guest

    I have 2 APIs that store/recall a void *. Since all I need to store is a
    32-bit struct, I pass the actual data (instead of a pointer to it) as a
    void *:

    typedef
    {
    UInt8 color;
    UInt8 index;
    UInt16 resID;
    } GadgetData;

    GadgetData data;

    data.color = ...

    FrmSetGadgetData( ..., ( void * ) *( UInt32 * ) &data );

    Now, I would like to retrieve this void * returned by FrmGetGadgetData
    back into a GadgetData struct:

    GadgetData data = FrmGetGadgetData( ... );

    but I can't find the proper way to cast a void * into my GadgetData
    struct.


    --
    Luc Le Blanc
     
    Luc Le Blanc, Nov 11, 2003
    #1
    1. Advertising

  2. Luc Le Blanc

    Jim Guest

    On Mon, 10 Nov 2003 21:26:36 -0500, Luc Le Blanc <>
    wrote:

    >I have 2 APIs that store/recall a void *. Since all I need to store is a
    >32-bit struct, I pass the actual data (instead of a pointer to it) as a
    >void *:
    >
    >typedef
    >{
    > UInt8 color;
    > UInt8 index;
    > UInt16 resID;
    >} GadgetData;
    >
    >GadgetData data;
    >
    >data.color = ...
    >
    >FrmSetGadgetData( ..., ( void * ) *( UInt32 * ) &data );
    >
    >Now, I would like to retrieve this void * returned by FrmGetGadgetData
    >back into a GadgetData struct:
    >
    >GadgetData data = FrmGetGadgetData( ... );
    >
    >but I can't find the proper way to cast a void * into my GadgetData
    >struct.


    data = *(GadgetData *)FrmGetGadgetData(...);

    But I think you're making a (totally OT) mistake in the Set part
    anyway.
     
    Jim, Nov 11, 2003
    #2
    1. Advertising

  3. in comp.lang.c i read:

    >I have 2 APIs that store/recall a void *. Since all I need to store is a
    >32-bit struct, I pass the actual data (instead of a pointer to it) as a
    >void *:


    serious mistake -- your code will have undefined behavior. use a union
    instead.

    --
    a signature
     
    those who know me have no need of my name, Nov 11, 2003
    #3
  4. "Jim" <> wrote in message
    news:...
    > On Mon, 10 Nov 2003 21:26:36 -0500, Luc Le Blanc <>
    > wrote:
    >
    > >I have 2 APIs that store/recall a void *. Since all I need to store is a
    > >32-bit struct, I pass the actual data (instead of a pointer to it) as a
    > >void *:
    > >
    > >typedef
    > >{
    > > UInt8 color;
    > > UInt8 index;
    > > UInt16 resID;
    > >} GadgetData;
    > >
    > >GadgetData data;
    > >
    > >data.color = ...
    > >
    > >FrmSetGadgetData( ..., ( void * ) *( UInt32 * ) &data );

    This doesn't do what the OP thinks it does. This doesn't store the actual
    contents of data as a 32 bit pointer, this stores a pointer to the data
    structure.

    > >
    > >Now, I would like to retrieve this void * returned by FrmGetGadgetData
    > >back into a GadgetData struct:
    > >
    > >GadgetData data = FrmGetGadgetData( ... );
    > >
    > >but I can't find the proper way to cast a void * into my GadgetData
    > >struct.

    >
    > data = *(GadgetData *)FrmGetGadgetData(...);
    >
    > But I think you're making a (totally OT) mistake in the Set part
    > anyway.

    Based on the OP's description (and not his code), that's not what he wants
    to do. He doesn't want to dereference the pointer FrmGetGadgetData returns.
    Instead, he wants to interpret the bit
    pattern of that pointer as a GadgetData structure.

    About the best he can do (and either involves Undefined Behavior, however,
    any
    method of doing what he wants involves Undefined Behavior):

    void *temp = FrmGetGadgetData(...);
    GadgetData data = *(GadgetData*)&temp;

    or

    GadgetData data;
    union {
    void *pointer;
    GadgetData data;
    } x;
    x.pointer = FrmGetGadgetData(...);
    data = x.data;

    I don't recommend either -- instead, I suggest he rethink the idea of saving
    the 32 bits as a "pointer" value.

    --
    poncho
     
    Scott Fluhrer, Nov 11, 2003
    #4
  5. In article <>, Luc Le Blanc <>
    wrote:

    > I have 2 APIs that store/recall a void *. Since all I need to store is a
    > 32-bit struct, I pass the actual data (instead of a pointer to it) as a
    > void *:
    >
    > typedef
    > {
    > UInt8 color;
    > UInt8 index;
    > UInt16 resID;
    > } GadgetData;
    >
    > GadgetData data;
    >
    > data.color = ...
    >
    > FrmSetGadgetData( ..., ( void * ) *( UInt32 * ) &data );
    >
    > Now, I would like to retrieve this void * returned by FrmGetGadgetData
    > back into a GadgetData struct:
    >
    > GadgetData data = FrmGetGadgetData( ... );
    >
    > but I can't find the proper way to cast a void * into my GadgetData
    > struct.


    The fact that you have to ask how to do this should be a strong hint
    that you shouldn't do it.

    Do the decent thing: void* p = malloc (sizeof GadgetData); memcpy (p,
    &data); etc.
     
    Christian Bau, Nov 11, 2003
    #5
  6. Luc Le Blanc

    Anupam Guest

    "Scott Fluhrer" <> wrote in message news:<NS_rb.7026$>...
    > "Jim" <> wrote in message
    > news:...
    > > On Mon, 10 Nov 2003 21:26:36 -0500, Luc Le Blanc <>
    > > wrote:
    > >
    > > >I have 2 APIs that store/recall a void *. Since all I need to store is a
    > > >32-bit struct, I pass the actual data (instead of a pointer to it) as a
    > > >void *:
    > > >
    > > >typedef
    > > >{
    > > > UInt8 color;
    > > > UInt8 index;
    > > > UInt16 resID;
    > > >} GadgetData;
    > > >
    > > >GadgetData data;
    > > >
    > > >data.color = ...
    > > >
    > > >FrmSetGadgetData( ..., ( void * ) *( UInt32 * ) &data );

    > This doesn't do what the OP thinks it does. This doesn't store the actual
    > contents of data as a 32 bit pointer, this stores a pointer to the data
    > structure.


    I don't agree with you here.
    Let's dissect : ( void * ) *( UInt32 * ) &data
    It says to the compiler:
    [ Consider only ( UInt32 * ) &data ]
    Hey just assume that &data which used to point to a GadgetData
    object in memory now points to an UInt32
    Now consider :
    ( void * ) * .....
    This says that take the object at this address ( now the compiler
    thinks that since this address points to an UInt32 object) ... which
    is a 32 bit object and forcibly say that this is a void * and pass it
    to the function... finally the actual data bytes are being sent as a
    32 bit pointer.


    >
    > > >
    > > >Now, I would like to retrieve this void * returned by FrmGetGadgetData
    > > >back into a GadgetData struct:
    > > >
    > > >GadgetData data = FrmGetGadgetData( ... );
    > > >
    > > >but I can't find the proper way to cast a void * into my GadgetData
    > > >struct.

    > >
    > > data = *(GadgetData *)FrmGetGadgetData(...);
    > >
    > > But I think you're making a (totally OT) mistake in the Set part
    > > anyway.

    > Based on the OP's description (and not his code), that's not what he wants
    > to do. He doesn't want to dereference the pointer FrmGetGadgetData returns.
    > Instead, he wants to interpret the bit
    > pattern of that pointer as a GadgetData structure.
    >
    > About the best he can do (and either involves Undefined Behavior, however,
    > any
    > method of doing what he wants involves Undefined Behavior):
    >
    > void *temp = FrmGetGadgetData(...);
    > GadgetData data = *(GadgetData*)&temp;


    Yup agreed.

    Im guessing that the OP would have tried :
    data = (GadgetData)(FrmGetGadgetData( ... ));
    This gave a "incompatible type conversion" error . This is because
    the C compiler thinks that this sort of a transformation need never be
    done on the semantics of the identifier of an object.
    >
    > or
    >
    > GadgetData data;
    > union {
    > void *pointer;
    > GadgetData data;
    > } x;
    > x.pointer = FrmGetGadgetData(...);
    > data = x.data;
    >
    > I don't recommend either -- instead, I suggest he rethink the idea of saving
    > the 32 bits as a "pointer" value.


    Ok now here's the biggest catch ... as to why I think this is such a
    *bad* idea. It's simply that this just may not work at all. Check out
    the fact that the sum of the fields of a struct may not equal the
    sizeof the struct at all. So your basic assumption that this is a 32
    bit struct may not always be true. As we go along theres a LOT of UB
    out here... but the start itself is one. Instead I would suggest that
    the OP make his own API's .. they'd be worth the effort.
     
    Anupam, Nov 11, 2003
    #6
  7. Luc Le Blanc

    Chris Torek Guest

    In article <>
    Anupam <> writes:
    > I don't agree with you here.
    >Let's dissect : ( void * ) *( UInt32 * ) &data
    >It says to the compiler:
    > [ Consider only ( UInt32 * ) &data ]
    > Hey just assume that &data which used to point to a GadgetData
    >object in memory now points to an UInt32


    Actually, this does not tell a compiler to "assume", but rather to
    *convert*. That is, if &data has type "pointer to GadgetData" (and
    some valid value of that type), the compiler must now convert that
    value to a new value, of type "pointer to UInt32". There is no
    requirement that the new value be useful in any way, in this
    particular case. Only "void *" (and by extension "char *") have
    constraints strong enough to enforce "usefulness" of such conversions.

    (On machines with multiple pointer formats, the computer must often
    execute at least one CPU instruction in order to perform the
    conversions produced by pointer casts. On computers with only
    one pointer format, the conversion takes no instructions, but
    is still a conversion.)

    > Now consider :
    > ( void * ) * .....
    > This says that take the object at this address ( now the compiler
    >thinks that since this address points to an UInt32 object) ...


    More precisely, the compiler must follow the pointer value -- or
    produce code to do this at runtime -- produced by the conversion
    you requested earlier. For this operation to have a useful,
    well-defined result, that pointer must in fact point to a valid
    object of type "UInt32" (whatever that is -- presumably the same
    as C99's uint32_t, though).

    >which is a 32 bit object


    (assuming the pointer is valid and the access produces a useful
    32-bit object, yes...)

    >and forcibly say that this is a void *


    Once again, a cast does not mean "pretend it is" or even "it IS",
    but rather "please convert it to". Conversions from integer to
    pointer are implementation-defined:

    [C99 draft, section 6.2.2.3]
    An integer may be converted to any pointer type. The result
    is implementation-defined, might not be properly aligned, and
    might not point to an entity of the referenced type.

    but are meant to do the "obvious thing" to anyone who is experienced
    with the machine's internal representations. (On some machines,
    reasonable people might even reasonably disagree as to what the
    "obvious thing" should be, so even this is a little iffy.)

    >Ok now here's the biggest catch ... as to why I think this is such a
    >*bad* idea. It's simply that this just may not work at all. Check out
    >the fact that the sum of the fields of a struct may not equal the
    >sizeof the struct at all. So your basic assumption that this is a 32
    >bit struct may not always be true. As we go along theres a LOT of UB
    >out here... but the start itself is one.


    Indeed. Additional possibilities include:

    - the struct is 32 bits but is not properly aligned for access
    as a "UInt32"
    - the struct is 32 bits but "void *" is not

    One case of the latter is rapidly becoming common today, with 64-bit
    CPUs. Of course, 64 value are likely to be able to hold 32 value
    bits without losing any bits, but the "thin ice" aspect of the
    whole approach should be obvious by now.
    --
    In-Real-Life: Chris Torek, Wind River Systems
    Salt Lake City, UT, USA (40°39.22'N, 111°50.29'W) +1 801 277 2603
    email: forget about it http://67.40.109.61/torek/index.html (for the moment)
    Reading email is like searching for food in the garbage, thanks to spammers.
     
    Chris Torek, Nov 11, 2003
    #7
  8. "Anupam" <> wrote in message
    news:...
    > "Scott Fluhrer" <> wrote in message

    news:<NS_rb.7026$>...
    > > "Jim" <> wrote in message
    > > news:...
    > > > On Mon, 10 Nov 2003 21:26:36 -0500, Luc Le Blanc <>
    > > > wrote:
    > > >
    > > > >I have 2 APIs that store/recall a void *. Since all I need to store

    is a
    > > > >32-bit struct, I pass the actual data (instead of a pointer to it) as

    a
    > > > >void *:
    > > > >
    > > > >typedef
    > > > >{
    > > > > UInt8 color;
    > > > > UInt8 index;
    > > > > UInt16 resID;
    > > > >} GadgetData;
    > > > >
    > > > >GadgetData data;
    > > > >
    > > > >data.color = ...
    > > > >
    > > > >FrmSetGadgetData( ..., ( void * ) *( UInt32 * ) &data );

    > > This doesn't do what the OP thinks it does. This doesn't store the

    actual
    > > contents of data as a 32 bit pointer, this stores a pointer to the data
    > > structure.

    >
    > I don't agree with you here.


    Oops, you are right -- I misread this.

    --
    poncho
     
    Scott Fluhrer, Nov 11, 2003
    #8
  9. Luc Le Blanc

    Anupam Guest

    Chris Torek <> wrote in message news:<boqrnk$43k$>...
    > In article <>
    > Anupam <> writes:
    > > I don't agree with you here.
    > >Let's dissect : ( void * ) *( UInt32 * ) &data
    > >It says to the compiler:
    > > [ Consider only ( UInt32 * ) &data ]
    > > Hey just assume that &data which used to point to a GadgetData
    > >object in memory now points to an UInt32

    >
    > Actually, this does not tell a compiler to "assume", but rather to
    > *convert*.


    Absolutely, I slipped up in the phraseology there.

    > (On machines with multiple pointer formats, the computer must often
    > execute at least one CPU instruction in order to perform the
    > conversions produced by pointer casts. On computers with only
    > one pointer format, the conversion takes no instructions, but
    > is still a conversion.)


    Well, well this is a nice fact ... my language showed my inner sort
    of feeling that pointers remain pointers ... no real manipulation is
    done ... shows the dangers of the one architecture mindset.

    [snip]

    I absolutely agree with all the comments there.
     
    Anupam, Nov 12, 2003
    #9
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Ollej Reemt
    Replies:
    7
    Views:
    602
    Jack Klein
    Apr 22, 2005
  2. Stig Brautaset

    `void **' revisited: void *pop(void **root)

    Stig Brautaset, Oct 25, 2003, in forum: C Programming
    Replies:
    15
    Views:
    836
    The Real OS/2 Guy
    Oct 28, 2003
  3. Enrico `Trippo' Porreca

    Casting const void * into void *

    Enrico `Trippo' Porreca, May 31, 2004, in forum: C Programming
    Replies:
    14
    Views:
    990
    August Derleth
    Jun 4, 2004
  4. Replies:
    5
    Views:
    881
    S.Tobias
    Jul 22, 2005
  5. Replies:
    1
    Views:
    435
    Victor Bazarov
    May 23, 2007
Loading...

Share This Page