19

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?

Shafik Yaghmour
  • 154,301
  • 39
  • 440
  • 740
Sneftel
  • 40,271
  • 12
  • 71
  • 104
  • I agree it's a bad wording, but I don't think any competent programmer would interpret it the way you suggest they might. – Lee Daniel Crocker Apr 04 '18 at 17:38
  • Ideally one shouldn't have to "interpret" a spec, especially to mean something other than what it literally says. – Sneftel Apr 04 '18 at 17:40
  • This is what the committee calls an "editorial defect". The wording is bad and should be fixed, but there's no real question about what the behavior ought to be. – zwol Apr 04 '18 at 17:42
  • Ideally. But human languages are not computer languages: they have ambiguity and nuance. If you have a better wording, feel free to suggest it to the committee. – Lee Daniel Crocker Apr 04 '18 at 17:43
  • the posted code for the union `foo' is NOT an actual union. Rather it only contains a single item (the anonymous struct) – user3629249 Apr 04 '18 at 18:38
  • regarding: `&f == &(f.b))` this expression will always fail, because the field 'b' is the second field in the struct – user3629249 Apr 04 '18 at 18:43
  • 2
    @user3629249 I don't think you've quite understood the question. By the letter of the C standard, `Foo` is a union containing two members, `a` and `b`. – Sneftel Apr 04 '18 at 18:49
  • 2
    "are considered to be members of the containing structure or union" is not the same thing as "are members of the containing structure or union". It seems pretty clear that the anonymous struct is a unit that is inserted into the union as a unit and the members of which are addressed by the labels of the members of the anonymous struct. There is no other reasonable alternative to being able to access the members of the anonymous struct. The phrase "are considered to be members of the containing structure or union" indicates the syntax for accessing a member of an anonymous struct. – Richard Chambers Apr 04 '18 at 19:09
  • 9
    This is [DR 499](http://www.open-std.org/jtc1/sc22/wg14/www/docs/n2148.htm#dr_499) ... `TL;DR;` they should not overlap. CC @LeeDanielCrocker – Shafik Yaghmour Apr 04 '18 at 19:40
  • @RichardChambers: I think the problem is that the Standard fails here and in many other places to properly separate the allocation of storage and the names/namespaces via which it can be accessed. For purpose of allocation, members of an anonymous struct within a union are contained within the struct within the union. For purposes of name space resolution, however, the members of the struct behave as members of the union. – supercat Apr 09 '18 at 22:49
  • @supercat that sounds reasonable. I am under the impression that much of the history of C has been attempting to refine the description and improve the language of the description with some improvements to the language along the way. C is actually a fairly small language with a fairly restricted set of keywords and the assembler of the PDP that K & R first worked with still exists in parts of the language. Like many things simple, a simple description has evolved into a more complex language description as the number of different target platforms increased uncovering ambiguities in the spec. – Richard Chambers Apr 10 '18 at 03:53
  • @ShafikYaghmour That is the answer. – Spenser Truex May 06 '18 at 14:56
  • @zwol: *The wording is bad and should be fixed, but there's no real question about what the behavior ought to be.* is far from clear. DR499 mentions at least one compiler (for IBM AIX) that implements the behavior different from the 'obvious' one. Of course, ShafikYaghmour is right on, as always. – alexsh May 24 '18 at 18:40
  • 1
    @ShafikYaghmour Can you turn your comment into an answer? It deserves upvotes! – Christian Hujer Jul 05 '18 at 19:55
  • 1
    @ChristianHujer done – Shafik Yaghmour Jul 05 '18 at 20:27
  • @SpenserTruex done – Shafik Yaghmour Jul 06 '18 at 06:43

1 Answers1

11

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.

S.S. Anne
  • 15,171
  • 8
  • 38
  • 76
Shafik Yaghmour
  • 154,301
  • 39
  • 440
  • 740