structure containing incomplete array type

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

    #1

    structure containing incomplete array type

    Is a structure containing an incomplete array as its last element (per
    paragraph 2 of section 6.7.2.1 of ISO/IEC 9899:1999 (E)) itself an
    incomplete type? That appears to be indicated by paragraph 22 of
    section 6.2.5. If so, that seems to make it difficult to allocate such
    structures, because sizeof() is not allowed on incomplete types
    (paragraph 1 of section 6.5.3.4).

    For instance, I've routinely done things like this:

    struct foo { int a; char b; double c []; };

    struct foo *alloc_foo (int s)
    {
    return (calloc (1, sizeof (struct foo) + sizeof (double) * s));
    }

    But section 6.2.5 seems to make this invalid.

    Is this the correct interpretation? If so, is there some other
    valid way to implement alloc_foo()?

    On the other hand, paragraph 3 of section 6.7.2.3 states that the
    declaration of a structure type is complete after the closing brace,
    without any caveat about incomplete elements of the structure.

    In writing this, I've started to wonder whether it's really specified
    that the size of an array of a particular element type is equal to the
    product of the array size and the size of the element type. I can't
    find anything suggesting that this is required. If it's not, is there
    some way given an integer expression to get the size of an array of that
    many elements of a particular type? Something like sizeof(double [s])?

    I used to think that using Ada's constrained record types was a hassle,
    but now I'm not convinced that the C99 incomplete array in a structure
    feature is any better.

    Thanks,
    Eric Smith

    [I'll watch for replies to the newsgroup, but if you want to reply by
    email, please remove the obvious spam-proofing from my email address.]
  • Jeremy Yallop

    #2
    Re: structure containing incomplete array type

    Eric Smith wrote:[color=blue]
    > Is a structure containing an incomplete array as its last element (per
    > paragraph 2 of section 6.7.2.1 of ISO/IEC 9899:1999 (E)) itself an
    > incomplete type? That appears to be indicated by paragraph 22 of
    > section 6.2.5. If so, that seems to make it difficult to allocate such
    > structures, because sizeof() is not allowed on incomplete types
    > (paragraph 1 of section 6.5.3.4).[/color]

    I think that a struct with a flexible array member has complete type,
    although the array has incomplete type. 6.7.2.1#16 covers the
    behaviour of sizeof on such structs:

    [T]he size of the structure shall be equal to the offset of the
    last element of an otherwise identical structure that replaces the
    flexible array member with an array of unspecified length.
    [color=blue]
    > In writing this, I've started to wonder whether it's really specified
    > that the size of an array of a particular element type is equal to the
    > product of the array size and the size of the element type. I can't
    > find anything suggesting that this is required.[/color]

    This follows directly from the definition of an array:

    An array type describes a contiguously allocated nonempty set of
    objects with a particular member object type, called the element
    type.

    Since the elements are "contiguous ly allocated", the size of the array
    is simply the sum of the sizes of the elements. This is different
    from structs, whose members are merely "sequential ly allocated". I
    think it follows from the way pointer arithmetic is defined, as well,
    but I haven't checked.
    [color=blue]
    > If it's not, is there some way given an integer expression to get
    > the size of an array of that many elements of a particular type?
    > Something like sizeof(double [s])?[/color]

    `sizeof(double[s])' is valid in C99 (and in C89 if `s' is an integer
    constant expression). `double[s]' is a type-name.

    Jeremy.

    Comment

    • Eric Smith

      #3
      Re: structure containing incomplete array type

      Jeremy Yallop <jeremy@jdyallo p.freeserve.co. uk> writes:[color=blue]
      > I think that a struct with a flexible array member has complete type,
      > although the array has incomplete type. 6.7.2.1#16 covers the
      > behaviour of sizeof on such structs:
      >
      > [T]he size of the structure shall be equal to the offset of the
      > last element of an otherwise identical structure that replaces the
      > flexible array member with an array of unspecified length.[/color]

      That's what I needed! Somehow I'd overlooked that paragraph.
      [color=blue]
      > This follows directly from the definition of an array:
      >
      > An array type describes a contiguously allocated nonempty set of
      > objects with a particular member object type, called the element
      > type.[/color]

      Ah! So the compiler can't add padding bytes for alignment. I had the
      mistaken impression that it was permissible for the compiler to add
      padding. For instance, on an architecture with four-byte integers
      required to be four-byte aligned, I thought some padding might be used
      in a case like this:

      struct foo_t { int a; char b; }; /* sizeof(struct foo_t) == 5 */

      struct foo_t bar [12];

      I'd previously expected that to result in the size of the array being
      96 bytes, but based on the array definition you've quoted (6.2.5#20),
      apparently it would only be 60 bytes. I suppose the compiler would be
      required to generate appropriate code for the misaligned integers, or
      to make sizeof(struct foo_t) be a multiple of four.

      Thanks!
      Eric

      Comment

      • CBFalconer

        #4
        Re: structure containing incomplete array type

        Eric Smith wrote:[color=blue]
        > Jeremy Yallop <jeremy@jdyallo p.freeserve.co. uk> writes:
        >[color=green]
        >> I think that a struct with a flexible array member has complete
        >> type, although the array has incomplete type. 6.7.2.1#16 covers
        >> the behaviour of sizeof on such structs:
        >>
        >> [T]he size of the structure shall be equal to the offset of the
        >> last element of an otherwise identical structure that replaces
        >> the flexible array member with an array of unspecified length.[/color]
        >
        > That's what I needed! Somehow I'd overlooked that paragraph.
        >[color=green]
        >> This follows directly from the definition of an array:
        >>
        >> An array type describes a contiguously allocated nonempty set
        >> of objects with a particular member object type, called the
        >> element type.[/color]
        >
        > Ah! So the compiler can't add padding bytes for alignment. I
        > had the mistaken impression that it was permissible for the
        > compiler to add padding. For instance, on an architecture with
        > four-byte integers required to be four-byte aligned, I thought
        > some padding might be used in a case like this:
        >
        > struct foo_t { int a; char b; }; /* sizeof(struct foo_t) == 5 */
        >
        > struct foo_t bar [12];
        >
        > I'd previously expected that to result in the size of the array
        > being 96 bytes, but based on the array definition you've quoted
        > (6.2.5#20), apparently it would only be 60 bytes. I suppose the
        > compiler would be required to generate appropriate code for the
        > misaligned integers, or to make sizeof(struct foo_t) be a
        > multiple of four.[/color]

        You were right the first time. It doesn't pad between array
        elements, but the elements themselves are padded so that they
        don't need it. That 5 above is probably 8.

        --
        Chuck F (cbfalconer@yah oo.com) (cbfalconer@wor ldnet.att.net)
        Available for consulting/temporary embedded and systems.
        <http://cbfalconer.home .att.net> USE worldnet address!

        Comment

        • Martin Ambuhl

          #5
          Re: structure containing incomplete array type

          Eric Smith wrote:[color=blue]
          > Is a structure containing an incomplete array as its last element (per
          > paragraph 2 of section 6.7.2.1 of ISO/IEC 9899:1999 (E)) itself an
          > incomplete type? That appears to be indicated by paragraph 22 of
          > section 6.2.5.[/color]

          "Appears to indicated"? If explicit words only "appear to indicate,"
          something is terribly wrong:
          [#23] ... A structure type
          containing a flexible array member is an incomplete type
          that cannot be completed.

          [color=blue]
          > If so, that seems to make it difficult to allocate such
          > structures, because sizeof() is not allowed on incomplete types
          > (paragraph 1 of section 6.5.3.4).[/color]

          Did you not read in that same section 6.7.2.1
          [#15] As a special case, the last element of a structure
          with more than one named member may have an incomplete array
          type. This is called a flexible array member, and the size
          of the structure shall be equal to the offset of the last
          element of an otherwise identical structure that replaces
          the flexible array member with an array of unspecified
          length.97) When an lvalue whose type is a structure with a
          flexible array member is used to access an object, it
          behaves as if that member were replaced with the longest
          array, with the same element type, that would not make the
          structure larger than the object being accessed; the offset
          of the array shall remain that of the flexible array member,
          even if this would differ from that of the replacement
          array. If this array would have no elements, then it
          behaves as if it had one element, but the behavior is
          undefined if any attempt is made to access that element or
          to generate a pointer one past it.


          [color=blue]
          > For instance, I've routinely done things like this:
          >
          > struct foo { int a; char b; double c []; };
          >
          > struct foo *alloc_foo (int s)
          > {
          > return (calloc (1, sizeof (struct foo) + sizeof (double) * s));
          > }
          >
          > But section 6.2.5 seems to make this invalid.[/color]

          Did you not read in that same section 6.7.2.1
          [#16] EXAMPLE Assuming that all array members are aligned
          the same, after the declarations:

          struct s { int n; double d[]; };
          struct ss { int n; double d[1]; };

          the three expressions:

          sizeof (struct s)
          offsetof(struct s, d)
          offsetof(struct ss, d)

          have the same value. The structure struct s has a flexible
          array member d.

          [#17] If sizeof (double) is 8, then after the following code
          is executed:

          struct s *s1;
          struct s *s2;
          s1 = malloc(sizeof (struct s) + 64);
          s2 = malloc(sizeof (struct s) + 46);

          and assuming that the calls to malloc succeed, the objects
          pointed to by s1 and s2 behave as if the identifiers had
          been declared as:

          struct { int n; double d[8]; } *s1;
          struct { int n; double d[5]; } *s2;

          [#18] Following the further successful assignments:

          s1 = malloc(sizeof (struct s) + 10);
          s2 = malloc(sizeof (struct s) + 6);

          they then behave as if the declarations were:

          struct { int n; double d[1]; } *s1, *s2;

          and:

          double *dp;
          dp = &(s1->d[0]); // Permitted
          *dp = 42; // Permitted
          dp = &(s2->d[0]); // Permitted
          *dp = 42; // Undefined behavior
          [color=blue]
          >
          > Is this the correct interpretation?[/color]

          For someone who quotes section numbers of the standard, you seem to have
          done precious little in the way of reading it.

          Comment

          • Jeremy Yallop

            #6
            Re: structure containing incomplete array type

            Martin Ambuhl wrote:[color=blue]
            > Eric Smith wrote:[color=green]
            >> Is a structure containing an incomplete array as its last element (per
            >> paragraph 2 of section 6.7.2.1 of ISO/IEC 9899:1999 (E)) itself an
            >> incomplete type? That appears to be indicated by paragraph 22 of
            >> section 6.2.5.[/color]
            >
            > "Appears to indicated"? If explicit words only "appear to indicate,"
            > something is terribly wrong:
            > [#23] ... A structure type
            > containing a flexible array member is an incomplete type
            > that cannot be completed.[/color]

            Those words don't appear in the standard, although they do in draft
            versions. I believe them to be false as a statement about C99.
            [color=blue][color=green]
            >> If so, that seems to make it difficult to allocate such
            >> structures, because sizeof() is not allowed on incomplete types
            >> (paragraph 1 of section 6.5.3.4).[/color]
            >
            > Did you not read in that same section 6.7.2.1[/color]

            The words you quote have also been changed in the standard and it
            would be unwise to rely upon them.
            [color=blue]
            > Did you not read in that same section 6.7.2.1
            > [#16] EXAMPLE[/color]

            The text of these examples has been changed between the final public
            draft and the actual standard.
            [color=blue]
            > For someone who quotes section numbers of the standard, you seem to have
            > done precious little in the way of reading it.[/color]

            "n869" is not the standard.

            Jeremy.

            Comment

            • Kevin Bracey

              #7
              Re: structure containing incomplete array type

              In message <40776266.D5F0C 0F2@yahoo.com>
              CBFalconer <cbfalconer@yah oo.com> wrote:
              [color=blue]
              > Eric Smith wrote:[color=green]
              > > Ah! So the compiler can't add padding bytes for alignment. I
              > > had the mistaken impression that it was permissible for the
              > > compiler to add padding. For instance, on an architecture with
              > > four-byte integers required to be four-byte aligned, I thought
              > > some padding might be used in a case like this:
              > >
              > > struct foo_t { int a; char b; }; /* sizeof(struct foo_t) == 5 */
              > >
              > > struct foo_t bar [12];
              > >
              > > I'd previously expected that to result in the size of the array
              > > being 96 bytes, but based on the array definition you've quoted
              > > (6.2.5#20), apparently it would only be 60 bytes. I suppose the
              > > compiler would be required to generate appropriate code for the
              > > misaligned integers, or to make sizeof(struct foo_t) be a
              > > multiple of four.[/color]
              >
              > You were right the first time. It doesn't pad between array
              > elements, but the elements themselves are padded so that they
              > don't need it. That 5 above is probably 8.[/color]

              Indeed, but as we were originally talking about flexible array members, it's
              worth noting one possible implementation quirk:

              struct foo_t { int a; char b; }; /* sizeof(struct foo_t) == 8 */
              struct jim_t { int a; char b; char c[1]; }; /* sizeof(struct jim_t) == 8 */
              struct bar_t { int a; char b; char c[]; } /* sizeof(struct bar_t) == 5 */

              That's quite possible, and a logical way to implement flexible array members.
              (The alternative would be to add 3 bytes of padding between b and c in
              bar_t). Structures with flexible array members cannot be elements of arrays,
              so trailing padding is not needed to ensure alignment of the int. Our
              implementation works in this way.

              FWIW, this is one of gcc's non-conformances to C99 - its sizeof(struct bar_t)
              == 8, but offsetof(bar_t, c) == 5.

              --
              Kevin Bracey, Principal Software Engineer
              Tematic Ltd Tel: +44 (0) 1223 503464
              182-190 Newmarket Road Fax: +44 (0) 1223 503458
              Cambridge, CB5 8HE, United Kingdom WWW: http://www.tematic.com/

              Comment

              Working...