21

I have the following question: How are anonymous structures (or unions) properly initialized according to the current C1X draft? Is this legal:

struct foo {
    int a;
    struct {
        int i;
        int j;
    };
    int b;
};

struct foo f = { 1, 2, 3, 4 };
struct foo g = { 1, { 2 }, 3 };

In GCC, g.j == 0 and g.b == 3, while in tcc g.j == 3 and g.b == 0. The current draft says:

"[...] unnamed members of objects of structure and union type do not participate in initialization. Unnamed members of structure objects have indeterminate value even after initialization.".

Can this be really true? Isn't

struct foo h = { 0 };

supposed to set all members to 0?

Thanks very much!

UPDATE:

Since anonymous members seem to be only useful when mixing structs/unions, how to initialize this correctly:

struct bar {
    int tag;
    union {
        double d;
        int i;
    };
};

? This gives errors in gcc < 4.6 and icc 11, but works in gcc 4.6, icc 12, clang and tcc:

struct bar a = { .tag = 1, .i = 42 };

This gives errors in clang and tcc, but works in gcc and icc:

struct bar b = { .tag = 1, { .i = 42 } };

Is the second one a violation of the standard?

Johan Bezem
  • 2,582
  • 1
  • 20
  • 47
jmuc
  • 1,551
  • 1
  • 14
  • 16
  • 1
    re update: if my interpretation of the standard is correct, the 2nd example would indeed be a violation: after `.tag = 1`, the current object (see 6.7.9 §17) will be associated with the first member `double d` of the anonymous union, which can't be initialized with `{ .i = 42 }`... – Christoph Feb 21 '11 at 13:56

3 Answers3

6

f and h should correctly initialize all members, as i and j are to be treated like members of struct foo (C1x 6.7.2.1 §13):

The members of an anonymous structure or union are considered to be members of the containing structure or union.

I don't think that gcc's initialization of g is correct, considering C1x 6.7.9 §9:

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.

§20 - which deals with sub-aggregates - contains no explicit statement relevant to the issue, so my best guess would be that §9 applies (but only to the aggregate itself, not to its members!).

The bottom line is that anonymous sub-aggregates don't exist as separate objects, ie tcc's behaviour should be correct...

Example code for my take on the issue:

struct foo
{
    struct bar { int i; }; // (1) unnamed, but tagged, ie *not* anonymous
    struct { int j; };     // (2) unnamed, but anonymous
    struct { int k; } baz; // (3) named, but not tagged
};

(1) takes no part in initialization, (2) initializes as though struct foo had an additional member named j, (3) initializes as a regular sub-aggregate.

If my interpretation is correct, anonymous structures only make sense if contained within a union: an anonymous structure within a structure is indistinguishable from a flat structure containing additional members.

Christoph
  • 164,997
  • 36
  • 182
  • 240
  • Thanks! So I should probably file a bug report to GCC (although they might not want to break old code). As it is allowed to add braces around constant (non-aggregate) initializers, these two should be identical: `struct foo f = { 0, { 0 }, 1 };` and `struct foo f = { 0, 0, 1};`? – jmuc Feb 21 '11 at 12:23
  • 1
    @jmuc: as far as I can tell, yes; however, it might be a good idea to contact the ISO working group - section 6.7.9 should deal with anonymous sub-aggregates either explicitly or at least as an example... – Christoph Feb 21 '11 at 12:33
1

All members that have names in your structure can be initialized. You just can't initialize the intermediate structures as such. But

struct foo f = { .a = 1, .i = 2, .j = 3, .b = 4 };

should do it.

Jens Gustedt
  • 76,821
  • 6
  • 102
  • 177
  • Thanks! But what happens if no designated initializers are used, as in `struct foo g = { 0, { 0 }, 1 };` ? GCC initializes the anonymous struct with the middle zero, but only when using braces. Is that standard-conform? – jmuc Feb 21 '11 at 11:21
  • @jmuc: I think that @Christoph is right with his answer, I don't think that this will be conform to the future standard since it says that basically the surrounding anonymous parts are to be ignored for all accesses. On the other hand you can't complain that gcc is not conform to C1x, they don't pretend to, don't they? – Jens Gustedt Feb 21 '11 at 14:29
-1

I haven't read the draft, I'm pretty sure unnamed and anonymous members are different. Unnamed would be something like

struct foo {
    int bar:1; /* named */
    int :31;   /* unnamed */
};
R.. GitHub STOP HELPING ICE
  • 208,859
  • 35
  • 376
  • 711
  • 1
    Yes, unnamed is different than anonymous, but unnamed **struct** or **union** members are called anonymous: "An unnamed member of structure type with no tag is called an anonymous structure; an unnamed member of union type with no tag is called an anonymous union. 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." – jmuc Feb 21 '11 at 11:19
  • 4
    @jmuc: If the members of the anonymous structure or union are "considered to be members of the containing structure or union", then it seems to me that while the anonymous structure or union is "unnamed", its members, as members of the containing structure or union, are named... – R.. GitHub STOP HELPING ICE Feb 21 '11 at 18:43