struct compatibility

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

    #1

    struct compatibility

    Hi,

    I'd like to know whether the following code is standard-compliant:


    struct generic {
    int x;
    int a[1];
    };


    void f(struct generic *s)
    {
    int i;

    for (i = 0; i < 10; i++)
    s->a[i] = i;
    }


    int main(void)
    {
    struct special {
    int x;
    int a[10];
    } s;

    f((struct generic *) &s);

    return 0;
    }


    Thanks,
    Christian
  • Marc Boyer

    #2
    Re: struct compatibility

    Le 31-01-2006, Christian Kandeler <christian.kand eler@hob.de> a écrit :[color=blue]
    > Hi,
    >
    > I'd like to know whether the following code is standard-compliant:
    >
    >
    > struct generic {
    > int x;
    > int a[1];
    > };
    >
    >
    > void f(struct generic *s)
    > {
    > int i;
    >
    > for (i = 0; i < 10; i++)
    > s->a[i] = i;
    > }
    >
    >
    > int main(void)
    > {
    > struct special {
    > int x;
    > int a[10];
    > } s;
    >
    > f((struct generic *) &s);
    >
    > return 0;
    > }[/color]

    Interesting question...
    If s was allocated on the heap, in C99, I think the code
    would be standart because of compatibility with flexible
    array member.

    The standart says that, 6.7.2.1/16-18, if there exist
    struct s {
    int x;
    int a[]; // No size !
    };

    Then, generic and s are 'compatible' when allocated
    with malloc, and also are special and s.
    In your example, there is no s, but I do not think
    it will create any difference for compilers.


    Marc Boyer

    Comment

    • Michael Mair

      #3
      Re: struct compatibility

      Christian Kandeler wrote:[color=blue]
      > Hi,
      >
      > I'd like to know whether the following code is standard-compliant:
      >
      >
      > struct generic {
      > int x;
      > int a[1];
      > };
      >
      > void f(struct generic *s)
      > {
      > int i;
      >
      > for (i = 0; i < 10; i++)
      > s->a[i] = i;
      > }
      >
      > int main(void)
      > {
      > struct special {
      > int x;
      > int a[10];
      > } s;
      >
      > f((struct generic *) &s);
      >
      > return 0;
      > }[/color]

      No, it is not. Do you want a C99 or C89 answer?
      Essentially, offsetof(struct generic, a) needs not
      be equal to offsetof(struct special, a)...

      BTW:
      struct special {
      struct generic access_me;
      int a[10 - ((sizeof (struct generic) - offsetof(struct generic,
      a))/sizeof (int))];
      } s;
      (with <stddef.h> included) gives you essentially the struct hack,
      so you have no "additional badness" related to other struct layout.
      The struct hack, even though not covered by the standard, works
      presumably on all known implementations .

      Cheers
      Michael
      --
      E-Mail: Mine is an /at/ gmx /dot/ de address.

      Comment

      • Christian Kandeler

        #4
        Re: struct compatibility

        Michael Mair wrote:
        [color=blue]
        > Christian Kandeler wrote:[color=green]
        >> I'd like to know whether the following code is standard-compliant:
        >>
        >> struct generic {
        >> int x;
        >> int a[1];
        >> };
        >>
        >> void f(struct generic *s)
        >> {
        >> int i;
        >>
        >> for (i = 0; i < 10; i++)
        >> s->a[i] = i;
        >> }
        >>
        >> int main(void)
        >> {
        >> struct special {
        >> int x;
        >> int a[10];
        >> } s;
        >>
        >> f((struct generic *) &s);
        >>
        >> return 0;
        >> }[/color]
        >
        > No, it is not. Do you want a C99 or C89 answer?
        > Essentially, offsetof(struct generic, a) needs not
        > be equal to offsetof(struct special, a)...[/color]

        Okay. But if I use a flexible array:

        struct generic {
        int x;
        int a[];
        }

        is the offset the same, then? I'm not sure if I can deduce that from the
        standard. If it is, does that make the rest of the code legal?


        Christian

        Comment

        • Christian Bau

          #5
          Re: struct compatibility

          In article <44be09F1b8k2U1 @individual.net >,
          Christian Kandeler <christian.kand eler@hob.de> wrote:
          [color=blue]
          > Michael Mair wrote:
          >[color=green]
          > > Christian Kandeler wrote:[color=darkred]
          > >> I'd like to know whether the following code is standard-compliant:
          > >>
          > >> struct generic {
          > >> int x;
          > >> int a[1];
          > >> };
          > >>
          > >> void f(struct generic *s)
          > >> {
          > >> int i;
          > >>
          > >> for (i = 0; i < 10; i++)
          > >> s->a[i] = i;
          > >> }
          > >>
          > >> int main(void)
          > >> {
          > >> struct special {
          > >> int x;
          > >> int a[10];
          > >> } s;
          > >>
          > >> f((struct generic *) &s);
          > >>
          > >> return 0;
          > >> }[/color]
          > >
          > > No, it is not. Do you want a C99 or C89 answer?
          > > Essentially, offsetof(struct generic, a) needs not
          > > be equal to offsetof(struct special, a)...[/color]
          >
          > Okay. But if I use a flexible array:
          >
          > struct generic {
          > int x;
          > int a[];
          > }
          >
          > is the offset the same, then? I'm not sure if I can deduce that from the
          > standard. If it is, does that make the rest of the code legal?[/color]

          With a flexible array, the offset if a is the same as the offset in
          _some_ variant of the struct with fixed array size. Lets say the
          compiler chooses one offset when the array size is < 10 and another one
          if array size is >= 10, and no other offset, then the offset in the
          flexible struct is one of those two offsets. But you don't know which
          one.

          The other difference is that with any fixed size array, the compiler can
          assume that the index is within the bounds. If you use a fixed size
          array of size 1, then the compiler can legally ignore the index you pass
          and always access array element 0, because that is the only one that you
          could access legally. With the flexible size array, the compiler must
          produce code that works no matter how large the array is. So here you
          have an improvement.

          Comment

          • Marc Boyer

            #6
            Re: struct compatibility

            Le 01-02-2006, Christian Kandeler <christian.kand eler@hob.de> a écrit :[color=blue]
            > Michael Mair wrote:[color=green]
            >> Christian Kandeler wrote:[color=darkred]
            >>> I'd like to know whether the following code is standard-compliant:
            >>>
            >>> struct generic {
            >>> int x;
            >>> int a[1];
            >>> };
            >>>
            >>> void f(struct generic *s)
            >>> {
            >>> int i;
            >>>
            >>> for (i = 0; i < 10; i++)
            >>> s->a[i] = i;
            >>> }
            >>>
            >>> int main(void)
            >>> {
            >>> struct special {
            >>> int x;
            >>> int a[10];
            >>> } s;
            >>>
            >>> f((struct generic *) &s);
            >>>
            >>> return 0;
            >>> }[/color]
            >>
            >> No, it is not. Do you want a C99 or C89 answer?
            >> Essentially, offsetof(struct generic, a) needs not
            >> be equal to offsetof(struct special, a)...[/color]
            >
            > Okay. But if I use a flexible array:
            >
            > struct generic {
            > int x;
            > int a[];
            > }
            >
            > is the offset the same, then? I'm not sure if I can deduce that from the
            > standard. If it is, does that make the rest of the code legal?[/color]

            No. There was a restriction I had not seen at first glance 6.7.2.1/17.
            "Assuming that all array membres are aligned the same".

            You should malloc s or add some code like
            assert( offsetof(generi c, a) == offsetof(specia l, a) ).


            Marc Boyer

            Comment

            • Barry Schwarz

              #7
              Re: struct compatibility

              On Tue, 31 Jan 2006 10:29:43 +0100, Christian Kandeler
              <christian.kand eler@hob.de> wrote:
              [color=blue]
              >Hi,
              >
              >I'd like to know whether the following code is standard-compliant:
              >
              >
              >struct generic {
              > int x;
              > int a[1];
              >};
              >
              >
              >void f(struct generic *s)
              >{
              > int i;
              >
              > for (i = 0; i < 10; i++)
              > s->a[i] = i;
              >}
              >
              >
              >int main(void)
              >{
              > struct special {
              > int x;
              > int a[10];
              > } s;
              >
              > f((struct generic *) &s);[/color]

              The standard guarantees that all pointers to struct have the same
              representation. Therefore, casting the value of &s will produce a
              representable result. It probably won't even change the
              representation.

              However, there is no guarantee that a struct special and a struct
              generic have the same alignment. If a struct generic has a more
              restrictive alignment that the struct special s does not meet, any
              attempt to dereference the address, as is done in function f, results
              in undefined behavior.

              Furthermore, the compiler is allowed to insert different quantities of
              padding between i and a in the two different structure types. It is
              therefore possible that function f is storing its values in padding of
              struct special s (if a struct special has the extra padding) or beyond
              the end of struct special s (if a struct generic has the extra
              padding). I'm not sure about the first but the second definitely
              invokes undefined behavior.

              Since it is possible for a compliant compiler to produce this
              undefined behavior, the answer has to be the code is not compliant.
              [color=blue]
              >
              > return 0;
              >}[/color]

              Comment

              Working...