6

I was looking into the C11 draft and it says

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.

So I constructed the following testcase

// struct type with no tag
typedef struct {
  unsigned char a;
  unsigned char b;
  // ... Some other members ...
  unsigned char w;
} AToW;

union
{
  AToW; // <- unnamed member
  unsigned char bytes[sizeof(AToW)];
} myUnion;

Clang and GCC both complain about the unnamed member, saying that the declaration has no effect. Did I do something wrong, or do they simply not support that feature yet?

Johannes Schaub - litb
  • 496,577
  • 130
  • 894
  • 1,212

1 Answers1

8

No, that's not an unnamed member.

An example is:

struct outer {
    int a;
    struct {
        int b;
        int c;
    };
    int d;
};

The inner structure containing members b and c is an unnamed member of struct outer. The members of this unnamed member, b and c, are considered to be members of the containing structure.

This is probably more useful with a contained union rather than a contained structure. In particular, it can be used to define something similar to a Pascal or Ada variant record:

enum variant_type { t_int, t_double, t_pointer, t_pair };
struct variant {
    enum variant_type type;
    union {
        int i;
        double d;
        void *p;
        struct {
            int x;
            int y;
        };
    };
};

This lets you refer to i, d, and p directly as members of a struct variant object rather than creating an artificial name for the variant portion. If some variants require more than one member, you can nest anonymous structures within the anonymous union.

(It differs from Pascal and Ada in that there's no mechanism to enforce which variant is active given the value of the type member; that's C for you.)

In your example, AToW is a typedef for a struct type that you defined previously. You're not permitted to have a bare

AToW;

in the middle of a struct definition, any more than you can have a bare

int;

C11 added the ability to define a nested anonymous struct within another struct, but only by defining a new anonymous struct type at that point. You can't have an anonymous struct member of a previously defined type. The language could have been defined to permit it, and the semantics would (I think) be reasonably straightforward -- but there wasn't much point in defining two different ways to do the same thing. (For "struct" in the above, read "struct or union".)

Quoting the N1570 draft (which is very close to the released 2011 ISO C standard), section 6.7.2.1 paragraph 13:

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.

A structure specifier consists of the keyword struct, followed by an optional identifier (the tag, omitted in this case), followed by a sequence of declarations enclosed in { and }. In your case, AToW is a type name, not a structure specifier, so it can't be used to define an anonymous structure.

Chnossos
  • 9,971
  • 4
  • 28
  • 40
Keith Thompson
  • 254,901
  • 44
  • 429
  • 631
  • I don't see the difference of that to my case, apart from the fact that you use a struct specifier as the type, and I used an ordinary identifier as the type. Why is my `AToW;` not an unnamed member? If I would change it to `AToW x;` it would become a named member. – Johannes Schaub - litb May 07 '14 at 20:16
  • @JohannesSchaub-litb: See the updated last paragraph of my answer. (TL;DR: Because the standard says so.) – Keith Thompson May 07 '14 at 20:24
  • *"You're not permitted to have a bare AToW; in the middle of a struct definition, any more than you can have a bare int;"* - does the quote I gave not permit it? It says "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" and goes on to define its semantics. So the question comes down to "Why is AToW; not an anonymous struct?" and I don't see it yet. "int;" is not, because "int" is not a struct type, that's easy. – Johannes Schaub - litb May 07 '14 at 20:27
  • *"You can't have an anonymous struct member of a previously defined type."*, I would be very interested in a quote of the spec that says this. That would indeed answer my question. – Johannes Schaub - litb May 07 '14 at 20:28
  • I just created a new tag-wiki for this. You seem to know facts, so you might want to double-check it: https://stackoverflow.com/tags/anonymous-struct/info . Unfortunately, the tag wiki does not answer my question, though :/ – Johannes Schaub - litb May 07 '14 at 20:35
  • @JohannesSchaub-litb: Updated, plus an example showing how this feature can be used to implement a variant record. – Keith Thompson May 07 '14 at 20:42
  • @JohannesSchaub-litb: I've updated the tag wiki to clarify that the feature was added in C11. – Keith Thompson May 07 '14 at 20:45
  • 1
    Thanks, it seems that newer drafts fixed this. The whole confusion was coming from a talk with a friend who told me that `struct A { struct B; };` would contain an anonymous struct. That would be an incompatibility with C++, so I wanted to look, and found that one might use a `typedef`. But it seems I was using a too old draft. – Johannes Schaub - litb May 07 '14 at 20:45
  • @JohannesSchaub-litb: Out of curiosity, which draft? – Keith Thompson May 07 '14 at 20:48
  • It is N1548, which I thought would be recent enough for not containing such errors (Dec2010). I failed. – Johannes Schaub - litb May 07 '14 at 20:49
  • @JohannesSchaub-litb: Ah, I see what you mean. I suspect the committee didn't intend to permit standalone typedef names, and cleaned up the wording in the later draft to make that clear. – Keith Thompson May 07 '14 at 20:59