Search code examples
clanguage-lawyerc11

Have anonymous structs and unions in C11 been incorrectly described?


Sayeth the C standard, regarding anonymous structs and unions:

6.7.2.1 p13. An unnamed member whose type specifier is a structure specifier with no tag is called an anonymous structure; an unnamed member whose type specifier is a union specifier 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.

Note emphasis: rather than the members of the anonymous struct/union being in the scope of the containing struct/union, they are fully members of it. But there are responsibilities attached to that:

6.7.2.1 p16. The size of a union is sufficient to contain the largest of its members. The value of at most one of the members can be stored in a union object at any time. A pointer to a union object, suitably converted, points to each of its members (or if a member is a bit-field, then to the unit in which it resides), and vice versa.

Taken together, those seem to imply that the members of an anonymous struct within a (named) union behave like co-located, mutually-exclusive members of the union. So the following should work:

union Foo
{
    struct
    {
        char a;
        char b;
    };
};

int main(void) {
    union Foo f;
    assert(&f == &(f.a) && &f == &(f.b));
}

Of course, it doesn't, and we wouldn't want it to... there'd be no reason for anonymous structs/unions if they worked like the above. Still, the Standard seems unambiguous on that point. Is there something I'm missing?


Solution

  • TL;DR

    This looks like a wording issue, they should not overlap.

    Details

    This is covered in Defect Report (DR) 499 which asks:

    Given the following code:

    union U {   
      struct {
        char B1;
        char B2;
        char B3;
        char B4;  
      };  
      int word; 
    } u;
    

    Does the storage of B1, B2, B3 and B4 overlap?

    According to 6.7.2.1#13, the members should overlap in storage as they become members of 'union U'.
    At least one implementation (GCC) seems to NOT consider them to be overlapping.
    At least one implementation (IBM's XL LE AIX) considers them to be overlapping as the standard currently states.

    And the committees response was:

    The storage does not overlap.

    A related issue is to be found in DR 502 and both may be resolved with coordinated wording changes.

    and (emphasis added)

    Change §6.7.2.1 p13 from:

    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.

    to:

    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 names of members of an anonymous structure or union are added to the name space of the containing structure or union. This applies recursively if the containing structure or union is also anonymous.

    would adequately resolve the issue.

    Update: After additional Committee Discussion, the final wording chosen was (emphasis added):

    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, keeping their structure or union layout. This applies recursively if the containing structure or union is also anonymous.