Johannes Schaub - litb Johannes Schaub - litb - 9 days ago 7
C Question

Is this a C11 anonymous struct?

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?

Answer

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.