Why Does C++11 Not Support Anonymous Structs, While C11 Does

Why does C++11 not support anonymous structs, while C11 does?

Little effort has been made to maintain compatibility between C++ and C as the two languages evolve. Notice that variable length stack arrays have been in C since 1999, but weren't included in C++11. While they generally don't introduce things that contradict one another, the C++ committee isn't exactly bending over backwards to make sure that C++11 is compatible with versions of C beyond C89.

Furthermore, this feature would be quite complex in C++, because a struct is nothing more than a class. And an anonymous struct/class should have all of the features of a regular struct/class, yes? Otherwise, what's the point of having it?

What would it mean to construct a nameless struct? How would you define the constructor? Something as simple as:

struct Foo
{
struct
{
size_t &x;
};
};

is simply not possible because the inner struct has no constructor. And there's no way to specify one. A struct cannot construct the members of another struct within it.

For something like this:

struct Foo
{
size_t outer;
struct
{
void SomeFunc();
size_t x;
};
};

What this pointer does SomeFunc get? What would the type of this be, the nameless and unnamed type? How would you even define SomeFunc outside of the struct? The name of SomeFunc can't be Foo::SomeFunc, because SomeFunc lives in an inner scope.

It's just too complex for C++ to deal with. And certainly not worthwhile enough to bother with adding that complexity for.

When are anonymous structs and unions useful in C11?

Anonymous union inside structures are very useful in practice. Consider that you want to implement a discriminated sum type (or tagged union), an aggregate with a boolean and either a float or a char* (i.e. a string), depending upon the boolean flag. With C11 you should be able to code

typedef struct {
bool is_float;
union {
float f;
char* s;
};
} mychoice_t;

double as_float(mychoice_t* ch)
{
if (ch->is_float) return ch->f;
else return atof(ch->s);
}

With C99, you'll have to name the union, and code ch->u.f and ch->u.s which is less readable and more verbose.

Another way to implement some tagged union type is to use casts. The Ocaml runtime gives a lot of examples.

The SBCL implementation of Common Lisp does use some union to implement tagged union types. And GNU make also uses them.

Is this a C11 anonymous struct?

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.

Have anonymous structs and unions in C11 been incorrectly described?

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.

Nested Anonymous Structs in c11

I'd skip everything called bit-fields, since they are non-standard and non-portable. What will happen when you use bit-fields on 8 or 16 bit stdint.h types, nobody knows. In addition you get padding issues because of the structs. And your code will be endianess-dependent. Overall a bad idea (but of course ok just for hobbyist purposes).

Instead, I would just define the type as:

typedef uint16_t opcode_t;

And then cook up some access macros:

#define I(op) ((op & 0xF000u) >> 12)
#define X(op) ((op & 0x0F00u) >> 8)
#define Y(op) ((op & 0x00F0u) >> 4)
#define NNN(op) (op & 0x0FFFu)
#define KK(op) (op & 0x00FFu)

This will translate to the best possible machine code and is 100% portable even across endianess.

You can even invent some higher level macro for generic access and type safety:

#define GET(op, type) _Generic(op, opcode_t: type(op))

Full example:

#include <stdint.h>
#include <stdio.h>
#include <inttypes.h>

typedef uint16_t opcode_t;

#define I(op) ((op & 0xF000u) >> 12)
#define X(op) ((op & 0x0F00u) >> 8)
#define Y(op) ((op & 0x00F0u) >> 4)
#define NNN(op) (op & 0x0FFFu)
#define KK(op) (op & 0x00FFu)

#define GET(op, type) _Generic(op, opcode_t: type(op))

int main (void)
{
opcode_t op = 0xABCD;

printf("I\t0x%"PRIX16 "\n", GET(op, I));
printf("X\t0x%"PRIX16 "\n", GET(op, X));
printf("Y\t0x%"PRIX16 "\n", GET(op, Y));
printf("NNN\t0x%"PRIX16 "\n", GET(op, NNN));
printf("KK\t0x%"PRIX16 "\n", GET(op, KK));
}

Output:

I       0xA
X 0xB
Y 0xC
NNN 0xBCD
KK 0xCD

C11 anonymous structs via typedefs?

This was apparently asked in a question to the C committee by Joseph S. Myers of the gcc team. And the answer is no, it is not valid in C11.

See the answer here:

http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1549.pdf

And Myers's comment:

This week's London WG14 meeting agreed to disallow the use of typedefs in declaring anonymous structure and union fields, as per N1549.

source http://gcc.gnu.org/ml/gcc-patches/2011-03/msg01151.html

The question was asked in SC22WG15.12205 see 5.28 SC22WG14.12205, Anonymous Structures (N1425) in http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1490.pdf

Why does C++ disallow anonymous structs?

As others have pointed out anonymous unions are permitted in standard C++, but anonymous structs are not.

The reason for this is that C supports anonymous unions but not anonymous structs*, so C++ supports the former for compatibility but not the latter because it's not needed for compatibility.

Furthermore, there's not much use to anonymous structs in C++. The use you demonstrate, to have a struct containing three floats which can be referred to either by .v[i], or .x, .y, and .z, I believe results in undefined behavior in C++. C++ does not allow you to write to one member of a union, say .v[1], and then read from another member, say .y. Although code that does this is not uncommon it is not actually well defined.

C++'s facilities for user-defined types provide alternative solutions. For example:

struct vector3 {
float v[3];
float &operator[] (int i) { return v[i]; }
float &x() { return v[0]; }
float &y() { return v[1]; }
float &z() { return v[2]; }
};

* C11 apparently adds anonymous structs, so a future revision to C++ may add them.

Why does the named reference to an anonymous struct , idiom described below need -fms-extensions to be compiled by clang/gcc

typedef struct OLHC {
union {
struct Price;
Price p;
};
double open;
} OHLC;

is not C11. It is C with extensions and is only allowed in gcc with -fms-extensions option.

C11 has anonymous structures and unions but the:

    struct Price;

in you struct OLHC is not allowed as a part of C11 anonymous structures.

Is there any version of gcc or clang which will compile this file with just the std=c11 flag without warnings.

No, C requires at least a warning.



Related Topics



Leave a reply



Submit