Flexible array member + variable length array

Discussion in 'C Programming' started by Adam Warner, Feb 3, 2005.

  1. Adam Warner

    Adam Warner Guest

    Hi all,

    With this structure that records the length of an array of pointers as its
    first member:

    struct array {
    ptrdiff_t length;
    void *ptr[];
    };

    How does one initialise this structure using a variable length array?

    ptrdiff_t len=10;
    {
    struct array a[len+1];
    ...
    }

    It appears the above code will only work to reserve space for len pointers
    if the sizeof length is the same as sizeof pointers to void and there is
    no padding between length and the pointers to void. Is there portable C99
    syntax that I have overlooked? (or will I have to create a VLA of type
    void * and keep casting the first argument to ptrdiff_t?)

    Thanks,
    Adam
     
    Adam Warner, Feb 3, 2005
    #1
    1. Advertising

  2. Adam Warner

    Michael Mair Guest

    Adam Warner wrote:
    > Hi all,
    >
    > With this structure that records the length of an array of pointers as its
    > first member:
    >
    > struct array {
    > ptrdiff_t length;
    > void *ptr[];
    > };
    >
    > How does one initialise this structure using a variable length array?
    >
    > ptrdiff_t len=10;
    > {
    > struct array a[len+1];
    > ...
    > }
    >
    > It appears the above code will only work to reserve space for len pointers
    > if the sizeof length is the same as sizeof pointers to void and there is
    > no padding between length and the pointers to void. Is there portable C99
    > syntax that I have overlooked? (or will I have to create a VLA of type
    > void * and keep casting the first argument to ptrdiff_t?)


    I am not sure what you are asking for. The example from the standard
    runs like this:

    (6.7.2.1)
    "
    17
    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.

    18
    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;
    "

    Structures with flexible array members of course cannot be
    put into arrays.


    Cheers
    Michael
    --
    E-Mail: Mine is an /at/ gmx /dot/ de address.
     
    Michael Mair, Feb 3, 2005
    #2
    1. Advertising

  3. Adam Warner

    Shan Guest

    Visit this page:

    http://gcc.gnu.org/ml/gcc/2002-04/msg00026.html

    Hope it helps.

    Cheers
    Shan

    Adam Warner wrote:
    > Hi all,
    >
    > With this structure that records the length of an array of pointers

    as its
    > first member:
    >
    > struct array {
    > ptrdiff_t length;
    > void *ptr[];
    > };
    >
    > How does one initialise this structure using a variable length array?
    >
    > ptrdiff_t len=10;
    > {
    > struct array a[len+1];
    > ...
    > }
    >
    > It appears the above code will only work to reserve space for len

    pointers
    > if the sizeof length is the same as sizeof pointers to void and there

    is
    > no padding between length and the pointers to void. Is there portable

    C99
    > syntax that I have overlooked? (or will I have to create a VLA of

    type
    > void * and keep casting the first argument to ptrdiff_t?)
    >
    > Thanks,
    > Adam
     
    Shan, Feb 3, 2005
    #3
  4. Adam Warner

    Shan Guest

    Shan wrote:
    > Visit this page:
    >
    > http://gcc.gnu.org/ml/gcc/2002-04/msg00026.html
    >
    > Hope it helps.
    >
    > Cheers
    > Shan
    >
    > Adam Warner wrote:
    > > Hi all,
    > >
    > > With this structure that records the length of an array of pointers

    > as its
    > > first member:
    > >
    > > struct array {
    > > ptrdiff_t length;
    > > void *ptr[];
    > > };
    > >
    > > How does one initialise this structure using a variable length

    array?
    > >
    > > ptrdiff_t len=10;
    > > {
    > > struct array a[len+1];
    > > ...
    > > }
    > >
    > > It appears the above code will only work to reserve space for len

    > pointers
    > > if the sizeof length is the same as sizeof pointers to void and

    there
    > is
    > > no padding between length and the pointers to void. Is there

    portable
    > C99
    > > syntax that I have overlooked? (or will I have to create a VLA of

    > type
    > > void * and keep casting the first argument to ptrdiff_t?)
    > >
    > > Thanks,
    > > Adam


    Sorry, i top posted by mistake....
     
    Shan, Feb 3, 2005
    #4
  5. Adam Warner

    Adam Warner Guest

    On Thu, 03 Feb 2005 10:29:48 +0100, Michael Mair wrote:

    > 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.
    >
    > 18
    > 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;
    > "
    >
    > Structures with flexible array members of course cannot be
    > put into arrays.


    Indeed. It looks like I was after alloca-style functionality (which is
    non-standard) to duplicate the example above on the stack instead of the
    heap.

    Regards,
    Adam
     
    Adam Warner, Feb 3, 2005
    #5
  6. On Thu, 03 Feb 2005 20:50:36 +1300, Adam Warner wrote:

    > Hi all,
    >
    > With this structure that records the length of an array of pointers as its
    > first member:
    >
    > struct array {
    > ptrdiff_t length;
    > void *ptr[];
    > };
    >


    This is a structure containing a C99 flexible array member.

    > How does one initialise this structure using a variable length array?


    You don't. Flexible array members and VLAs are different and unrelated
    constructs. Flexible array members are designed to be allocated using
    malloc() and friends, e.g.

    struct array *p = malloc(sizeof *p + len * sizeof *p->ptr);

    > ptrdiff_t len=10;
    > {
    > struct array a[len+1];
    > ...
    > }


    You can't make arrays of structures containing flexible array members
    because the size of each element is not known or fixed.

    Lawrence
     
    Lawrence Kirby, Feb 3, 2005
    #6
  7. Adam Warner

    S.Tobias Guest

    Lawrence Kirby <> wrote:
    > On Thu, 03 Feb 2005 20:50:36 +1300, Adam Warner wrote:


    > > Hi all,
    > >
    > > With this structure that records the length of an array of pointers as its
    > > first member:
    > >
    > > struct array {
    > > ptrdiff_t length;
    > > void *ptr[];
    > > };
    > >


    > This is a structure containing a C99 flexible array member.


    > > How does one initialise this structure using a variable length array?


    > You don't. Flexible array members and VLAs are different and unrelated
    > constructs. Flexible array members are designed to be allocated using
    > malloc() and friends, e.g.


    > struct array *p = malloc(sizeof *p + len * sizeof *p->ptr);


    Well, if an object was declared with the type struct with FAM, then
    you actually could initialize it's leading members, couldn't you?
    (Of course, declaring such objects would be against the purpose
    of FAM.)
    (Note: you cannot initialize FAM itself, even if the struct were
    the first member of a suitable union, because FAM is ignored in
    all contexts, except `sizeof', `.' and `->'.)

    > > ptrdiff_t len=10;
    > > {
    > > struct array a[len+1];
    > > ...
    > > }


    > You can't make arrays of structures containing flexible array members
    > because the size of each element is not known or fixed.


    Would you please kindly elaborate on that?

    Indeed, FAMs (flexible array members) and VLAs are different. FAMs are
    described in 6.7.2.1p16. The size of a struct with a FAM is the
    offset of the FAM, therefore such a struct is not an incomplete type.
    It is not variably modified type either, because it does not contain a
    VLA type (the definition of VM types is in 6.7.5p3).

    The last place I looked was in array declarators, and all I found was
    in 6.7.5.2p1:
    # The element type shall not be an incomplete or function type.

    I see nothing that would forbid to create arrays of structs with FAM.

    +++

    However, I tried this program with Comeau compiler in C99 mode:

    struct flex
    {
    int i;
    int tail[];
    };

    int main()
    {
    struct flex f;
    int s = sizeof(struct flex);
    struct flex a[5];
    }

    [...]
    "t.c", line 11: error: type containing an unknown-size array is not allowed
    struct flex a[5];
    ^

    It seems to accept a declared object (`f') of type struct flex, but
    rejects an array for some reason.

    --
    Stan Tobias
    mailx `echo LID | sed s/[[:upper:]]//g`
     
    S.Tobias, Feb 4, 2005
    #7
  8. Adam Warner

    Michael Mair Guest

    S.Tobias wrote:
    > Lawrence Kirby <> wrote:
    >
    >>On Thu, 03 Feb 2005 20:50:36 +1300, Adam Warner wrote:

    >
    >
    >>>Hi all,
    >>>
    >>>With this structure that records the length of an array of pointers as its
    >>>first member:
    >>>
    >>>struct array {
    >>> ptrdiff_t length;
    >>> void *ptr[];
    >>>};
    >>>

    >
    >
    >>This is a structure containing a C99 flexible array member.

    >
    >
    >>>How does one initialise this structure using a variable length array?

    >
    >
    >>You don't. Flexible array members and VLAs are different and unrelated
    >>constructs. Flexible array members are designed to be allocated using
    >>malloc() and friends, e.g.

    >
    >
    >> struct array *p = malloc(sizeof *p + len * sizeof *p->ptr);

    >
    >
    > Well, if an object was declared with the type struct with FAM, then
    > you actually could initialize it's leading members, couldn't you?
    > (Of course, declaring such objects would be against the purpose
    > of FAM.)
    > (Note: you cannot initialize FAM itself, even if the struct were
    > the first member of a suitable union, because FAM is ignored in
    > all contexts, except `sizeof', `.' and `->'.)
    >
    >
    >>>ptrdiff_t len=10;
    >>>{
    >>> struct array a[len+1];
    >>> ...
    >>>}

    >
    >
    >>You can't make arrays of structures containing flexible array members
    >>because the size of each element is not known or fixed.

    >
    >
    > Would you please kindly elaborate on that?
    >
    > Indeed, FAMs (flexible array members) and VLAs are different. FAMs are
    > described in 6.7.2.1p16. The size of a struct with a FAM is the
    > offset of the FAM, therefore such a struct is not an incomplete type.
    > It is not variably modified type either, because it does not contain a
    > VLA type (the definition of VM types is in 6.7.5p3).
    >
    > The last place I looked was in array declarators, and all I found was
    > in 6.7.5.2p1:
    > # The element type shall not be an incomplete or function type.
    >
    > I see nothing that would forbid to create arrays of structs with FAM.
    >
    > +++
    >
    > However, I tried this program with Comeau compiler in C99 mode:
    >
    > struct flex
    > {
    > int i;
    > int tail[];
    > };
    >
    > int main()
    > {
    > struct flex f;
    > int s = sizeof(struct flex);
    > struct flex a[5];
    > }
    >
    > [...]
    > "t.c", line 11: error: type containing an unknown-size array is not allowed
    > struct flex a[5];
    > ^
    >
    > It seems to accept a declared object (`f') of type struct flex, but
    > rejects an array for some reason.


    Because there is no guarantee that the alignment requirements hold
    in the sense that there is padding at the end.
    Example: Let sizeof(int)==4, sizeof(short)==2 and the alignment
    requirements equal to the size of the type.
    Hence,
    struct s1 {
    int i;
    char c;
    }
    will have a size of 8, but
    struct s2 {
    int i;
    char c;
    short s[];
    }
    has as size of 6 as we assume that
    sizeof(structs2)==offsetof(struct s2,s)
    and offsetof(struct s2,s)==offsetof(struct s3,s)
    with
    struct s3 {
    int i;
    char c;
    short s[1];
    }
    which follows from the (non-normative) example 6.7.2.1#17


    Cheers
    Michael
    --
    E-Mail: Mine is an /at/ gmx /dot/ de address.
     
    Michael Mair, Feb 5, 2005
    #8
  9. Adam Warner

    S.Tobias Guest

    Michael Mair <> wrote:
    > S.Tobias wrote:
    > > Lawrence Kirby <> wrote:


    [snippage]

    > >>You can't make arrays of structures containing flexible array members
    > >>because the size of each element is not known or fixed.

    > >
    > >
    > > Would you please kindly elaborate on that?
    > >
    > > Indeed, FAMs (flexible array members) and VLAs are different. FAMs are
    > > described in 6.7.2.1p16. The size of a struct with a FAM is the
    > > offset of the FAM, therefore such a struct is not an incomplete type.
    > > It is not variably modified type either, because it does not contain a
    > > VLA type (the definition of VM types is in 6.7.5p3).
    > >
    > > The last place I looked was in array declarators, and all I found was
    > > in 6.7.5.2p1:
    > > # The element type shall not be an incomplete or function type.
    > >
    > > I see nothing that would forbid to create arrays of structs with FAM.
    > >
    > > +++
    > >
    > > However, I tried this program with Comeau compiler in C99 mode:
    > >

    [snip code]
    > >
    > > [...]
    > > "t.c", line 11: error: type containing an unknown-size array is not allowed
    > > struct flex a[5];
    > > ^
    > >
    > > It seems to accept a declared object (`f') of type struct flex, but
    > > rejects an array for some reason.


    Thank you for answering, however I disagree with your POV.

    > Because there is no guarantee that the alignment requirements hold
    > in the sense that there is padding at the end.


    But the Standard does not make any requirements for alignment
    (it merely allows them); it's up to the implementation fulfill them.

    > Example: Let sizeof(int)==4, sizeof(short)==2 and the alignment
    > requirements equal to the size of the type.
    > Hence,
    > struct s1 {
    > int i;
    > char c;
    > }
    > will have a size of 8, but
    > struct s2 {
    > int i;
    > char c;
    > short s[];
    > }
    > has as size of 6 as we assume that
    > sizeof(structs2)==offsetof(struct s2,s)


    Yes, but what's the point? On an architecture without alignment
    this shouldn't be a problem, should it?

    I think you use your logic in the wrong direction. My reasoning
    would be that since the Standard doesn't forbid structs with FAM
    being elements of an array, they are allowed. It means that on
    an implementation with int alignment 4 bytes, the compiler must
    provide padding bits so that sizeof(struct s2) == 8.

    > and offsetof(struct s2,s)==offsetof(struct s3,s)
    > with
    > struct s3 {
    > int i;
    > char c;
    > short s[1];
    > }
    > which follows from the (non-normative) example 6.7.2.1#17


    No, the Standard is very clear that it does not guarantee this
    (footnote 106; and the word "Assuming" in the example).

    Note that 6.7.2.1p16 does not provide any recipe for building
    struct s2 type; it uses words "an array of unspecified length",
    which means it is up to the implementation to decide what length
    should be the most suitable.

    +++

    I think it not wrong to imagine that a FAM is a "member" which
    represents the bytes _after_ the body of the struct object
    (ie. the FAM does not strictly belong to the struct).

    ===

    For others' convenience, here's the full quote of 6.7.2.1p16:

    # 16 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. With two exceptions,
    # the flexible array member is ignored. First, 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.106) Second,
    # when a . (or ->) operator has a left operand that is (a pointer
    # to) a structure with a flexible array member and the right
    # operand names that member, 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, 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.
    #
    # 106) The length is unspecified to allow for the fact that
    # implementations may give array members different alignments
    # according to their lengths.

    --
    Stan Tobias
    mailx `echo LID | sed s/[[:upper:]]//g`
     
    S.Tobias, Feb 6, 2005
    #9
  10. Adam Warner

    Kevin Bracey Guest

    In message <>
    "S.Tobias" <> wrote:

    > I think you use your logic in the wrong direction. My reasoning
    > would be that since the Standard doesn't forbid structs with FAM
    > being elements of an array, they are allowed. It means that on
    > an implementation with int alignment 4 bytes, the compiler must
    > provide padding bits so that sizeof(struct s2) == 8.


    Wrong. 6.7.2.1p2:

    "...the last member of a structure with more than one named member
    may have incomplete array type; such a structure ... shall not be a
    member of a structure or an element of an array."

    This is precisely to cope with alignment issues. On our implementation,
    int has alignment 4, and given

    struct s1 {
    int i;
    char c;
    };

    struct s2 {
    int i;
    char c;
    short s[];
    };

    struct s1 has size 8, and struct s2 has size 6 (because sizeof(struct s2)
    must equal offsetof(struct s2, s)), just as Michael suggests. Thus any
    struct s2s placed in an array would be misaligned. Fortunately, the standard
    forbids this.

    There is a Defect Report #282 about sizeof such a structure, but it's bogus
    as far as I can see - they're suggesting that they have to put padding before
    s[] to make s2 be size 8 for alignment, but what they've missed is that s2
    does not have to meet alignment requirements, because of the array
    restriction, so s2 can be left unpadded.

    --
    Kevin Bracey, Principal Software Engineer
    Tematic Ltd Tel: +44 (0) 1223 503464
    182-190 Newmarket Road Fax: +44 (0) 1728 727430
    Cambridge, CB5 8HE, United Kingdom WWW: http://www.tematic.com/
     
    Kevin Bracey, Feb 10, 2005
    #10
  11. Adam Warner

    S.Tobias Guest

    Re: [thanks] Flexible array member + variable length array

    Kevin Bracey <> wrote:
    > In message <>
    > "S.Tobias" <> wrote:


    > > I think you use your logic in the wrong direction. My reasoning
    > > would be that since the Standard doesn't forbid structs with FAM
    > > being elements of an array, they are allowed. It means that on

    [snip]

    > Wrong. 6.7.2.1p2:


    > "...the last member of a structure with more than one named member
    > may have incomplete array type; such a structure ... shall not be a
    > member of a structure or an element of an array."


    Shame on me having missed that part! Many thanks!

    --
    Stan Tobias
    mailx `echo LID | sed s/[[:upper:]]//g`
     
    S.Tobias, Feb 10, 2005
    #11
    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. =?utf-8?Q?Bo=C5=A1tjan?= Jerko

    Passing list with flexible length to C extension

    =?utf-8?Q?Bo=C5=A1tjan?= Jerko, Nov 21, 2003, in forum: Python
    Replies:
    1
    Views:
    263
    Michael Hudson
    Nov 21, 2003
  2. DevarajA

    flexible array member

    DevarajA, Nov 12, 2005, in forum: C Programming
    Replies:
    2
    Views:
    353
    DevarajA
    Nov 13, 2005
  3. Replies:
    2
    Views:
    394
  4. Hallvard B Furuseth

    Alignment of struct with flexible array member

    Hallvard B Furuseth, Dec 13, 2006, in forum: C Programming
    Replies:
    3
    Views:
    373
    christian.bau
    Dec 13, 2006
  5. Catsquotl
    Replies:
    6
    Views:
    140
    Catsquotl
    Jun 29, 2009
Loading...

Share This Page