structure containing incomplete array type

Discussion in 'C Programming' started by Eric Smith, Apr 9, 2004.

  1. Eric Smith

    Eric Smith Guest

    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 )?

    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.]
    Eric Smith, Apr 9, 2004
    #1
    1. Advertising

  2. Eric Smith wrote:
    > 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).


    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.

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


    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 "contiguously 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 "sequentially allocated". I
    think it follows from the way pointer arithmetic is defined, as well,
    but I haven't checked.

    > 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 )?


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

    Jeremy.
    Jeremy Yallop, Apr 10, 2004
    #2
    1. Advertising

  3. Eric Smith

    Eric Smith Guest

    Jeremy Yallop <> writes:
    > 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.


    That's what I needed! Somehow I'd overlooked that paragraph.

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


    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
    Eric Smith, Apr 10, 2004
    #3
  4. Eric Smith

    CBFalconer Guest

    Eric Smith wrote:
    > Jeremy Yallop <> writes:
    >
    >> 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.

    >
    > That's what I needed! Somehow I'd overlooked that paragraph.
    >
    >> 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.

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


    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 () ()
    Available for consulting/temporary embedded and systems.
    <http://cbfalconer.home.att.net> USE worldnet address!
    CBFalconer, Apr 10, 2004
    #4
  5. Eric Smith wrote:
    > 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.


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


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


    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.



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


    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

    >
    > Is this the correct interpretation?


    For someone who quotes section numbers of the standard, you seem to have
    done precious little in the way of reading it.
    Martin Ambuhl, Apr 10, 2004
    #5
  6. Martin Ambuhl wrote:
    > Eric Smith wrote:
    >> 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.

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


    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.

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

    >
    > Did you not read in that same section 6.7.2.1


    The words you quote have also been changed in the standard and it
    would be unwise to rely upon them.

    > Did you not read in that same section 6.7.2.1
    > [#16] EXAMPLE


    The text of these examples has been changed between the final public
    draft and the actual standard.

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


    "n869" is not the standard.

    Jeremy.
    Jeremy Yallop, Apr 10, 2004
    #6
  7. Eric Smith

    Kevin Bracey Guest

    In message <>
    CBFalconer <> wrote:

    > Eric Smith wrote:
    > > 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.

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


    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/
    Kevin Bracey, Apr 13, 2004
    #7
    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. gk245
    Replies:
    2
    Views:
    1,185
    Christopher Benson-Manica
    May 6, 2006
  2. xuthee

    tree data structure: incomplete type error

    xuthee, Jul 18, 2007, in forum: C Programming
    Replies:
    2
    Views:
    693
    xuthee
    Jul 19, 2007
  3. Replies:
    1
    Views:
    944
    Richard Bos
    Jan 17, 2008
  4. arcadio

    Array has incomplete element type. GCC bug?

    arcadio, Jun 23, 2008, in forum: C Programming
    Replies:
    11
    Views:
    2,153
  5. Luca Forlizzi

    Questions on incomplete structure type

    Luca Forlizzi, Nov 5, 2010, in forum: C Programming
    Replies:
    4
    Views:
    584
    Marcin Grzegorczyk
    Nov 5, 2010
Loading...

Share This Page