user2371524
user2371524

Reputation:

Initialization of anonymous struct, workaround for gcc 4.9

I have the following struct types:

typedef struct PG_Point PG_Point;
struct PG_Point
{
    int x;
    int y;
};

typedef struct PG_Size PG_Size;
struct PG_Size
{
    int width;
    int height;
};

typedef struct PG_Bounds PG_Bounds;
struct PG_Bounds
{
    union
    {
        struct
        {
            PG_Point topLeft;
            PG_Size size;
        };
        struct
        {
            struct
            {
                int x;
                int y;
            };
            struct
            {
                int width;
                int height;
            };
        };
    };
};

with the following initializers:

#define PG_Point_init(ix, iy) {.x=(ix), .y=(iy)}
#define PG_Size_init(iwidth, iheight) {.width=(iwidth), .height=(iheight)}

#define PG_Bounds_init(ix, iy, iwidth, iheight) { \
    .topLeft=PG_Point_init((ix),(iy)), \
    .size=PG_Size_init((iwidth),(iheight)) }

From what I understand, it's correct in to initialize the fields of an anonymous struct as if they were directly fields of the containing struct? But with gcc 4.9.2, this gives the following warning:

warning: missing initializer for field ‘size’ of ‘struct <anonymous>’ [-Wmissing-field-initializers]

It works if I change the initializer to this version:

#define PG_Bounds_init(ix, iy, iwidth, iheight) {{{ \
    .topLeft=PG_Point_init((ix),(iy)), \
    .size=PG_Size_init((iwidth),(iheight)) }}}

That is, explicitly having the union and struct as sub aggregates.

Is this even allowed? Do I have to expect other compilers to reject this?

Upvotes: 1

Views: 877

Answers (1)

John Bollinger
John Bollinger

Reputation: 180211

From what I understand, it's correct in c11 to initialize the fields of an anonymous struct as if they were directly fields of the containing struct?

There are two parts to that. First of all, we need to tackle the question of whether such members can be initialized at all, because Paragraph 6.7.2.1/13 identifies anonymous structure and union members as specific kinds of "unnamed members", and paragraph 6.7.9/9 says

Except where explicitly stated otherwise, for the purposes of this subclause unnamed members of objects of structure and union type do not participate in initialization.

The rest of section 6.7.9 (Initialization) nowhere says anything that I would interpret as explicitly applying to anonymous structure and anonymous union members themselves, but I don't think the intent is to prevent initialization of the named members of anonymous members, especially given that they are considered members of the containing structure or union (see below). Thus, I do not interpret the standard to forbid the initialization you are trying to perform.

So yes, I read C11 to allow your initializer and to specify that it has the effect you appear to intend. In particular, paragraph 6.7.2.1/13 of the standard says, in part,

The members of an anonymous structure or union are considered to be members of the containing structure or union. This applies recursively if the containing structure or union is also anonymous.

Your initializer therefore satisfies the constraint in paragraph 6.7.9/7, that the designators within specify names of members of the current object (in your case, a struct PG_Bounds). The following paragraphs of section 6.7.9 present the semantics for initializers, and I see no reason to interpret them to specify anything other than initialization of the overall object with the values you have provided.

At this point, I reiterate that gcc is issuing a warning, not rejecting your code, and in this case I think the warning is spurious. I wrote a test program such as I suggested in comments that you do, and tried it on gcc 4.8.5 in C11 mode. Although gcc emitted the same warning you presented (but only with -Wextra enabled), I was able to demonstrate that your initializer initialized all members of a subject struct PG_Bounds to the intended values.


You also observe that gcc does not warn if you change the initializer to a version that uses nested brace-enclosed initializers, and ask

Is this even allowed? Do I have to expect other compilers to reject this?

This could be viewed as more problematic with respect to paragraph 6.7.9/9, so in that sense it is perhaps riskier. I am uncertain whether there is any compiler that actually rejects it or does the wrong thing with it. I think the intent of the standard is to allow this initializer, but I would prefer the other form, myself.

Upvotes: 2

Related Questions