struct versioning

Collapse
This topic is closed.
X
X
 
  • Time
  • Show
Clear All
new posts
  • Pres

    struct versioning

    Noticed that several windows API's take a size parameter.
    i.e. one of the members of the struct is dwSize which is supposed
    to be initialized by client code, by taking the sizeof of the struct.

    I assume this is to enable versioning of structures

    /* first version of struct */
    typedef struct { int dwSize; type1 t1; } A;

    /* 2nd version of struct in new version of the library */

    typedef struct { int dwSize; type1 t1; } A_v1; // Old struct renamed to
    A_v1
    typedef struct { int dwSize; type1 t1; type 2;} A;


    So their implementation of function will look like
    // Impl in v1 of Lib
    void fn(A * ptr) { /* Implementation */ }

    //Impl in v2 of lib

    void fn_v1(A_v1 * ptr) { /* Renamed old fn to fn_v1 - Implementation */

    void fn(A * ptr)
    {
    if (ptr->dwSize == sizeof(A_v1)
    {
    fn_v1(); return;
    }
    /* New Implementation Below */

    }

    Is my assumption correct - is this something like what they would
    be doing?

    Is this fully standard compliant or are they taking liberties with their
    close knowledge of the internals of the compiler.
    Assume lib_v1 is compiled with compiler cl_v1 & lib_v2 is compiled
    with compiler cl_v2, then it is safe to assume that sizeof(A_v1) would
    be the same when compiled with different versions of the same compiler?

    i.e. can sizeof(A_v1) can when compiled with gcc v2 as compared to
    gcc v1?
    If it cannot, then can it change when compiled by two totally different
    compilers?

    Any other gotchas?


  • Chris Torek

    #2
    Re: struct versioning

    In article <fv7i4t$hco$1@n ews.datemas.deP res <invalid.email@ spam.comwrote:
    >Noticed that several windows API's take a size parameter.
    >i.e. one of the members of the struct is dwSize which is supposed
    >to be initialized by client code, by taking the sizeof of the struct.
    >
    >I assume this is to enable versioning of structures ...
    It might be; but using sizes for version information is, er, "not
    very clever". Consider, e.g., what happens if a "V1" data structure
    has a total of 12 bytes of information, V2 adds four (giving 16),
    V3 adds another 8 (now 24), and then V4 simplifies it all and
    shrinks the number down to 20. When V5 comes out, and needs four
    more byte of information, the "24" size will have already been in
    use (in V3).

    In other words, if you want a *version* tag, use a version tag,
    not a size tag.
    >Is my assumption correct - is this something like what they would
    >be doing?
    (I have no idea. It is hard enough to speculate on what someone
    intended when you have access to all of the code; give me just a
    vague description and it becomes that much harder.)
    >Is this fully standard compliant or are they taking liberties with their
    >close knowledge of the internals of the compiler.
    There is nothing "nonstandar d" about it, but nothing particularly
    "standard" either. "Taking liberties" is not really a justifiable
    claim at this point though:
    >Assume lib_v1 is compiled with compiler cl_v1 & lib_v2 is compiled
    >with compiler cl_v2, then it is safe to assume that sizeof(A_v1) would
    >be the same when compiled with different versions of the same compiler?
    This is never a completely *safe* assumption. Any two different
    compilers could do different things. However, if the two are
    *intended* to inter-operate -- as is usually the case for a newer
    version of a compiler from the same vendor -- then things that
    change the size (and hence layout) of struct types are generally
    viewed as "bugs" in the compiler. :-) The reason is that changing
    *anything* about the layout and/or representation results in
    "binary incompatibility " with the other (or previous) compiler.

    Consider, for instance, CPUs with "endian-ness" bits in instructions.
    (Typically a load or store instruction, on such a CPU, has an
    endian-control bit, so you might do:

    load_little_end ian r1, mem
    load_big_endian r2, mem

    and so on. The spelling of this instruction is "lda" on the SPARC
    and the endian-ness is provided as a third argument, but it is
    encoded in the instruction nonetheless[%]. The "lda" instruction
    runs just as fast as the "non-annotated" "ld" instruction, too.
    The regular "ld" instruction takes the endian-ness from the CPU
    endian-ness control.) On such a CPU, we can write incompatible
    compilers (or incompatible compiler versions) just by changing the
    endian-ness controls. This has no effect on the *sizes* of the
    data being loaded and stored, just on the in-memory representations .
    >i.e. can sizeof(A_v1) can when compiled with gcc v2 as compared to
    >gcc v1? ... can it change when compiled by two totally different
    >compilers?
    It can, but these are often considered bugs. However, consider
    what happens if you use compiler "packing" switches, either from
    things like #pragma or from command-line switches ("-fpack-struct",
    "/pack:N", "optimize=memfo otprint", etc). Using these is like
    changing implementations : the code you get with "pack-all-structs"
    is not binary-compatible with the code you get without it.

    [% Actually, this varies: you can either have it inside the
    instruction, or in the %asi register, as I recall. If it is in
    the instruction, you must give up the offset addressing modes.]
    --
    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: gmail (figure it out) http://web.torek.net/torek/index.html

    Comment

    • Ernie Wright

      #3
      Re: struct versioning

      Pres wrote:
      Noticed that several windows API's take a size parameter.
      i.e. one of the members of the struct is dwSize which is supposed
      to be initialized by client code, by taking the sizeof of the struct.
      >
      I assume this is to enable versioning of structures
      Yes.

      To see a specific example, look up Microsoft's definition of the
      BITMAPINFOHEADE R, BITMAPV4HEADER, and BITMAPV5HEADER structures.
      Is this fully standard compliant or are they taking liberties with their
      close knowledge of the internals of the compiler.
      Assume lib_v1 is compiled with compiler cl_v1 & lib_v2 is compiled
      with compiler cl_v2, then it is safe to assume that sizeof(A_v1) would
      be the same when compiled with different versions of the same compiler?
      You have this part backwards. Compilers that claim to produce output
      that works with Windows must be binary-compatible with Windows, not the
      other way around.

      Windows specifies the structure packing, the endianness, the sizes of
      its primitive types (e.g. DWORD), and the calling conventions for any
      code that calls or is called by any part of the Windows API.

      - Ernie http://home.comcast.net/~erniew

      Comment

      • shuchaoo@gmail.com

        #4
        Re: struct versioning

        On Apr 30, 12:24 am, "Pres" <invalid.em...@ spam.comwrote:
        Noticed that several windows API's take a size parameter.
        i.e. one of the members of the struct is dwSize which is supposed
        to be initialized by client code, by taking the sizeof of the struct.
        >
        I assume this is to enable versioning of structures
        >
        /* first version of struct */
        typedef struct { int dwSize; type1 t1; } A;
        >
        /* 2nd version of struct in new version of the library */
        >
        typedef struct { int dwSize; type1 t1; } A_v1; // Old struct renamed to
        A_v1
        typedef struct { int dwSize; type1 t1; type 2;} A;
        >
        So their implementation of function will look like
        // Impl in v1 of Lib
        void fn(A * ptr) { /* Implementation */ }
        >
        //Impl in v2 of lib
        >
        void fn_v1(A_v1 * ptr) { /* Renamed old fn to fn_v1 - Implementation */
        >
        void fn(A * ptr)
        {
        if (ptr->dwSize == sizeof(A_v1)
        {
        fn_v1(); return;
        }
        /* New Implementation Below */
        >
        }
        >
        Is my assumption correct - is this something like what they would
        be doing?
        >
        Is this fully standard compliant or are they taking liberties with their
        close knowledge of the internals of the compiler.
        Assume lib_v1 is compiled with compiler cl_v1 & lib_v2 is compiled
        with compiler cl_v2, then it is safe to assume that sizeof(A_v1) would
        be the same when compiled with different versions of the same compiler?
        >
        i.e. can sizeof(A_v1) can when compiled with gcc v2 as compared to
        gcc v1?
        If it cannot, then can it change when compiled by two totally different
        compilers?
        >
        Any other gotchas?
        are you sure sizeof(A_v1) !=....... != sizeof(A_vn)?
        why not defines a version field?

        Comment

        Working...