Casting a void * into a 32-bit struct

Collapse
This topic is closed.
X
X
 
  • Time
  • Show
Clear All
new posts
  • Luc Le Blanc

    Casting a void * into a 32-bit struct

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

    FrmSetGadgetDat a( ..., ( void * ) *( UInt32 * ) &data );

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

    GadgetData data = FrmGetGadgetDat a( ... );

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


    --
    Luc Le Blanc

  • Jim

    #2
    Re: Casting a void * into a 32-bit struct

    On Mon, 10 Nov 2003 21:26:36 -0500, Luc Le Blanc <lleblanc@cam.o rg>
    wrote:
    [color=blue]
    >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 = ...
    >
    >FrmSetGadgetDa ta( ..., ( void * ) *( UInt32 * ) &data );
    >
    >Now, I would like to retrieve this void * returned by FrmGetGadgetDat a
    >back into a GadgetData struct:
    >
    >GadgetData data = FrmGetGadgetDat a( ... );
    >
    >but I can't find the proper way to cast a void * into my GadgetData
    >struct.[/color]

    data = *(GadgetData *)FrmGetGadgetD ata(...);

    But I think you're making a (totally OT) mistake in the Set part
    anyway.

    Comment

    • those who know me have no need of my name

      #3
      Re: Casting a void * into a 32-bit struct

      in comp.lang.c i read:
      [color=blue]
      >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 *:[/color]

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

      --
      a signature

      Comment

      • Scott Fluhrer

        #4
        Re: Casting a void * into a 32-bit struct


        "Jim" <spam@ihug.com. au> wrote in message
        news:q3o0rvsva0 1e9tust5hibt6q4 ami1dp54f@4ax.c om...[color=blue]
        > On Mon, 10 Nov 2003 21:26:36 -0500, Luc Le Blanc <lleblanc@cam.o rg>
        > wrote:
        >[color=green]
        > >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 = ...
        > >
        > >FrmSetGadgetDa ta( ..., ( void * ) *( UInt32 * ) &data );[/color][/color]
        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.
        [color=blue][color=green]
        > >
        > >Now, I would like to retrieve this void * returned by FrmGetGadgetDat a
        > >back into a GadgetData struct:
        > >
        > >GadgetData data = FrmGetGadgetDat a( ... );
        > >
        > >but I can't find the proper way to cast a void * into my GadgetData
        > >struct.[/color]
        >
        > data = *(GadgetData *)FrmGetGadgetD ata(...);
        >
        > But I think you're making a (totally OT) mistake in the Set part
        > anyway.[/color]
        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 FrmGetGadgetDat a 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 = FrmGetGadgetDat a(...);
        GadgetData data = *(GadgetData*)& temp;

        or

        GadgetData data;
        union {
        void *pointer;
        GadgetData data;
        } x;
        x.pointer = FrmGetGadgetDat a(...);
        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



        Comment

        • Christian Bau

          #5
          Re: Casting a void * into a 32-bit struct

          In article <3FB048DC.C2EF2 23@cam.org>, Luc Le Blanc <lleblanc@cam.o rg>
          wrote:
          [color=blue]
          > 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 = ...
          >
          > FrmSetGadgetDat a( ..., ( void * ) *( UInt32 * ) &data );
          >
          > Now, I would like to retrieve this void * returned by FrmGetGadgetDat a
          > back into a GadgetData struct:
          >
          > GadgetData data = FrmGetGadgetDat a( ... );
          >
          > but I can't find the proper way to cast a void * into my GadgetData
          > struct.[/color]

          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.

          Comment

          • Anupam

            #6
            Re: Casting a void * into a 32-bit struct

            "Scott Fluhrer" <sfluhrer@ix.ne tcom.com> wrote in message news:<NS_rb.702 6$nz.476@newsre ad2.news.pas.ea rthlink.net>...[color=blue]
            > "Jim" <spam@ihug.com. au> wrote in message
            > news:q3o0rvsva0 1e9tust5hibt6q4 ami1dp54f@4ax.c om...[color=green]
            > > On Mon, 10 Nov 2003 21:26:36 -0500, Luc Le Blanc <lleblanc@cam.o rg>
            > > wrote:
            > >[color=darkred]
            > > >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 = ...
            > > >
            > > >FrmSetGadgetDa ta( ..., ( void * ) *( UInt32 * ) &data );[/color][/color]
            > 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.[/color]

            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.

            [color=blue]
            >[color=green][color=darkred]
            > > >
            > > >Now, I would like to retrieve this void * returned by FrmGetGadgetDat a
            > > >back into a GadgetData struct:
            > > >
            > > >GadgetData data = FrmGetGadgetDat a( ... );
            > > >
            > > >but I can't find the proper way to cast a void * into my GadgetData
            > > >struct.[/color]
            > >
            > > data = *(GadgetData *)FrmGetGadgetD ata(...);
            > >
            > > But I think you're making a (totally OT) mistake in the Set part
            > > anyway.[/color]
            > 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 FrmGetGadgetDat a 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 = FrmGetGadgetDat a(...);
            > GadgetData data = *(GadgetData*)& temp;[/color]

            Yup agreed.

            Im guessing that the OP would have tried :
            data = (GadgetData)(Fr mGetGadgetData( ... ));
            This gave a "incompatib le 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.[color=blue]
            >
            > or
            >
            > GadgetData data;
            > union {
            > void *pointer;
            > GadgetData data;
            > } x;
            > x.pointer = FrmGetGadgetDat a(...);
            > data = x.data;
            >
            > I don't recommend either -- instead, I suggest he rethink the idea of saving
            > the 32 bits as a "pointer" value.[/color]

            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.

            Comment

            • Chris Torek

              #7
              Re: Casting a void * into a 32-bit struct

              In article <aa67fba3.03111 10601.34be0c28@ posting.google. com>
              Anupam <anupam_mukherj ee@persistent.c o.in> writes:[color=blue]
              > 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[/color]

              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.)
              [color=blue]
              > 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) ...[/color]

              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).
              [color=blue]
              >which is a 32 bit object[/color]

              (assuming the pointer is valid and the access produces a useful
              32-bit object, yes...)
              [color=blue]
              >and forcibly say that this is a void *[/color]

              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.)
              [color=blue]
              >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.[/color]

              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.

              Comment

              • Scott Fluhrer

                #8
                Re: Casting a void * into a 32-bit struct


                "Anupam" <anupam_mukherj ee@persistent.c o.in> wrote in message
                news:aa67fba3.0 311110601.34be0 c28@posting.goo gle.com...[color=blue]
                > "Scott Fluhrer" <sfluhrer@ix.ne tcom.com> wrote in message[/color]
                news:<NS_rb.702 6$nz.476@newsre ad2.news.pas.ea rthlink.net>...[color=blue][color=green]
                > > "Jim" <spam@ihug.com. au> wrote in message
                > > news:q3o0rvsva0 1e9tust5hibt6q4 ami1dp54f@4ax.c om...[color=darkred]
                > > > On Mon, 10 Nov 2003 21:26:36 -0500, Luc Le Blanc <lleblanc@cam.o rg>
                > > > wrote:
                > > >
                > > > >I have 2 APIs that store/recall a void *. Since all I need to store[/color][/color][/color]
                is a[color=blue][color=green][color=darkred]
                > > > >32-bit struct, I pass the actual data (instead of a pointer to it) as[/color][/color][/color]
                a[color=blue][color=green][color=darkred]
                > > > >void *:
                > > > >
                > > > >typedef
                > > > >{
                > > > > UInt8 color;
                > > > > UInt8 index;
                > > > > UInt16 resID;
                > > > >} GadgetData;
                > > > >
                > > > >GadgetData data;
                > > > >
                > > > >data.color = ...
                > > > >
                > > > >FrmSetGadgetDa ta( ..., ( void * ) *( UInt32 * ) &data );[/color]
                > > This doesn't do what the OP thinks it does. This doesn't store the[/color][/color]
                actual[color=blue][color=green]
                > > contents of data as a 32 bit pointer, this stores a pointer to the data
                > > structure.[/color]
                >
                > I don't agree with you here.[/color]

                Oops, you are right -- I misread this.

                --
                poncho


                Comment

                • Anupam

                  #9
                  Re: Casting a void * into a 32-bit struct

                  Chris Torek <nospam@elf.eng .bsdi.com> wrote in message news:<boqrnk$43 k$1@elf.eng.bsd i.com>...[color=blue]
                  > In article <aa67fba3.03111 10601.34be0c28@ posting.google. com>
                  > Anupam <anupam_mukherj ee@persistent.c o.in> writes:[color=green]
                  > > 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[/color]
                  >
                  > Actually, this does not tell a compiler to "assume", but rather to
                  > *convert*.[/color]

                  Absolutely, I slipped up in the phraseology there.
                  [color=blue]
                  > (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.)[/color]

                  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.

                  Comment

                  Working...