Search code examples
cstructinitializationlanguage-lawyerflexible-array-member

Why is this initialization of a structure with a flexible array member invalid but valid with an fixed size array member?


The C standard states (emphasize mine):

21 EXAMPLE 2 After the declaration:

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

the structure struct s has a flexible array member d. [...]


22 Following the above declaration:

struct s t1 = { 0 };         // valid
struct s t2 = { 1, { 4.2 }}; // invalid
t1.n = 4;                    // valid
t1.d[0] = 4.2;               // might be undefined behavior

The initialization of t2 is invalid (and violates a constraint) because struct s is treated as if it did not contain member d.

Source: C18, §6.7.2.1/20 + /21

I do not understand the explanation of "because struct s is treated as if it did not contain member d"

If I use the initializer of { 1, { 4.2 }};, the { 4.2 } part is to initialize the flexible array member; To be precise to initialize the flexible array member to be consisted of one element and initialize this element to the value 4.2 and thus stuct s is treated as it has member d or not?

This sentence makes no sense in my eyes.

  • Why does the standard say, that { 4.2 } wouldn't initialize/denote the flexible array member and thus the structure would be treated as if it has no member d?

If I use a fixed size array, this notation works and initializes the member with no complain:

struct foo {
    int x;
    double y[1];
};

int main (void)
{
    struct foo a = { 1, { 2.3 } };
}

Evidence

  • Why is this initialization invalid when the structure has an flexible array member but valid when the structure has an fixed size array member?

Could you elaborate that?


I've read:

Why does static initialization of flexible array member work?

and

How to initialize a structure with flexible array member

and

Flexible array members can lead to undefined behavior?

and others but none of them answers me what this sentence wants to explain and why exactly this this is invalid.


Related:


Solution

  • I guess this is a language defect. While it might make no sense to initialize a flexible array member, the standard needs to address that issue somewhere. I can't find such normative text anywhere.

    The definition of a flexible array member is, C17 6.7.2.1/18:

    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. In most situations, the flexible array member is ignored. In particular, the size of the structure is as if the flexible array member were omitted except that it may have more trailing padding than the omission would imply.

    From this we learn that a flexible array member is an incomplete array type. We do not however learn in what situations the flexible array member is ignored, save for when calculating the size of the struct. "In most situations" isn't helpful and is the defect - this needed to be expanded to an exhaustive list, including the behavior of flexible array members when part of an initializer list. Otherwise one may assume that it behaves just like any other array of incomplete type.

    C17 6.2.5/22:

    An array type of unknown size is an incomplete type.

    And then the rules for initialization say, C17 6.7.9:

    The type of the entity to be initialized shall be an array of unknown size or a complete object type that is not a variable length array type.

    So far there is no normative text saying that we are not allowed to provide an initializer for a flexible array member - on the contrary. The example in the question (C17 6.7.2.1 example 21) is not normative, since examples aren't normative in ISO standards. The example doesn't mention which constraint that is violated, nor does it mention where it says that the flexible array member must be ignored.

    I suppose I'd probably file a DR about this.