108

Some C++ compilers permit anonymous unions and structs as an extension to standard C++. It's a bit of syntactic sugar that's occasionally very helpful.

What's the rationale that prevents this from being part of the standard? Is there a technical roadblock? A philosophical one? Or just not enough of a need to justify it?

Here's a sample of what I'm talking about:

struct vector3 {
  union {
    struct {
      float x;
      float y;
      float z;
    };
    float v[3];
  };
};

My compiler will accept this, but it warns that "nameless struct/union" is a non-standard extension to C++.

underscore_d
  • 6,309
  • 3
  • 38
  • 64
Adrian McCarthy
  • 45,555
  • 16
  • 123
  • 175
  • 4
    Clearly there's some confusion about what you mean. Could you please provide an example of code that only compiles due to a compiler extension? – Rob Kennedy Feb 12 '10 at 18:18
  • 87
    Notice that there are two concepts, that sound similar, but are vastly different: *unnamed structs* and *anonymous structs*. The first is this one, which C++ supports: `struct { int i; } a; a.i = 0;` (the type has no name). The second is this one, which C++ does *not* support: `struct { int i; }; i = 0;` (the type has no name, and it escapes into the surrounding scope). C++, however, *does* support both unnamed and anonymous *unions*. – Johannes Schaub - litb Feb 12 '10 at 18:39
  • This looks like the rather interesting VMMLib vector library. I believe the problem is that the union contains an unnamed struct, but I'm unsure. – greyfade Feb 12 '10 at 21:05
  • 1
    FWIW It's "anonmyous", not "unnamed", and unions _are_ supported as litb says. http://stackoverflow.com/q/14248044/560648 – Lightness Races in Orbit Jan 10 '13 at 01:42
  • @LightnessRacesinOrbit: "Nameless" was a direct quote from the compiler warning. I've updated the question with a link to the documentation from the warning message. – Adrian McCarthy Jan 10 '13 at 18:02
  • 1
    @AdrianMcCarthy: That's fine (FSVO "fine"; pesky compiler being cryptic), but precisely "unnamed" is an unrelated, standard concept. – Lightness Races in Orbit Jan 10 '13 at 18:07

7 Answers7

60

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.

bames53
  • 86,085
  • 15
  • 179
  • 244
  • 3
    "C++ does not allow you to write to one member of a union[...] and then read from another member" - **unless** said members are standard-layout objects and share a _common initial sequence_ of members of their own, and you're writing/reading _their_ members within said common initial sequence. That _is_ allowed (i.e. defined). – underscore_d Jun 09 '16 at 14:29
  • 6
    @underscore_d: Yes, if the types are standard layout with a common initial sequence. However, a struct can never alias with an *array* in this way, because the "common initial sequence" rules of C++ state that a common initial sequence can only be between *structs*. Arrays are not mentioned, so they cannot alias like this. – Nicol Bolas Aug 22 '16 at 00:02
  • @NicolBolas Oh, haha - believe me - I have wished many times that arrays and other primitives were included in this allowance! But I've not thought much about the possible practical limitations on that, so probably it's not as simple as it currently seems. My comment was more general but might've risked implying by omission that I thought arrays were included in this, so thanks for adding that in. – underscore_d Aug 22 '16 at 07:53
  • "The reason for this is that C supports anonymous unions but not anonymous structs" -- No. Your footnote clarifies that you were talking about C99 or earlier here. The term "anonymous union" does not appear anywhere in the C99 standard. GCC claims in an diagnostic (with -std=c99 -pedantic options) that "ISO C99 doesn't support unnamed structs/unions". The standard doesn't mention anything about unnamed members other than unnamed bit-fields. I'm not entirely sure if struct-declarations are declarations, but if they are, anonymous unions are a constraint violation per 6.7p2, at best undefined. –  Sep 08 '17 at 23:45
  • Ah, figured out how it's supposed to work. struct-declarations aren't declarations, so 6.7p2 doesn't apply to them, but the syntax requires each struct-declaration to contain a struct-declarator. The only struct-declarator that is syntactically allowed to omit the declarator is an unnamed bit-field. In C99, anonymous unions are therefore a constraint violation outside of structures, and a syntax error as members of structures. –  Sep 09 '17 at 12:22
  • +1 for the usage of C++ guarantees for built-in arrays and remark about C11. Coming from C# I still fail to understand why a lot of people dislike `type& prop()` access methods. – Sergey.quixoticaxis.Ivanov May 26 '18 at 23:36
  • @NicolBolas to handle the common initial sequence, can't the array also be wrapped in an anonymous struct? e.g. `union Point { struct { int x, y; }; struct { int v[2]; }; };` – Matt Eding Jul 22 '21 at 15:41
25

I'll say, you can clean up your vector3 declaration by just using a union

union vector3 {
  struct { float x, y, z; } ;
  float v[3] ;
} ;

Sure, anonymous structures was an MSVC extension. But ISO C11 permits it now, and gcc allows it, and so does Apple's llvm compiler.

Why in C11 and not C++11? I'm not sure, but practically speaking most (gcc++, MSVC++ and Apple's C++ compiler) C++ compilers support them.

bobobobo
  • 64,917
  • 62
  • 258
  • 363
  • 1
    The only things you can't do with a union are [have static data members, or use inheritance](http://msdn.microsoft.com/en-us/library/5dxy4b7b.aspx). – bobobobo Oct 15 '12 at 22:27
  • 3
    Thanks. I never new a union could be used like a struct or class. – Adrian McCarthy Oct 17 '12 at 20:10
  • I know Sun studio didn't not support anonymous struct prior to C++11 by default. If you are writing cross platform code and compilers are not upgraded to C+11 then don't use anonymous struct. – irsis May 12 '15 at 05:30
  • If ISO permits this, why doesn't it work with GCC? https://stackoverflow.com/questions/72137275/c-union-struct-with-struct-member-works-on-clang-and-msvc-but-not-gcc – Aaron Franke May 14 '22 at 23:26
3

Not sure what you mean. Section 9.5 of the C++ spec, clause 2:

A union of the form

union { member-specification } ;

is called an anonymous union; it defines an unnamed object of unnamed type.

You can do things like this too:

void foo()
{
  typedef
  struct { // unnamed, is that what you mean by anonymous?
    int a;
    char b;
  } MyStructType; // this is more of a "C" style, but valid C++ nonetheless

  struct { // an anonymous struct, not even typedef'd
    double x;
    double y;
  } point = { 1.0, 3.4 };
}

Not always very useful... although sometimes useful in nasty macro definitions.

Dan
  • 5,929
  • 6
  • 42
  • 52
  • 15
    -1 because it's saying that it defines an anonymous struct. See comments above on the question - you are defining an unnamed struct, not an anonymous one. – Johannes Schaub - litb Mar 26 '10 at 21:47
1

Unions can be anonymous; see the Standard, 9.5 paragraph 2.

What purpose do you see an anonymous struct or class as fulfilling? Before speculating why something isn't in the Standard, I'd like to have some idea why it should be, and I don't see a use for an anonymous struct.

David Thornley
  • 56,304
  • 9
  • 91
  • 158
1

Based on the edit, the comments, and this MSDN article: Anonymous Structures, I'll hazard a guess - it fits poorly with the concept of encapsulation. I wouldn't expect a member of a class to mess with my class namespace beyond merely adding one member. Furthermore, changes to the anonymous structure can affect my class without permission.

JonM
  • 830
  • 8
  • 10
  • 1
    Due to the way anonymous struct/unions are created (it's special, inline syntax that cannot be hidden except by a macro) you cannot be surprised that some member you're using is an anonymous member. So I don't think this reasoning makes any sense. The actual reason is that anonymous unions _are_ supported in C++, for C compatibility only. C doesn't support anonymous structs (until C11) and so C++ doesn't either. – bames53 Oct 08 '12 at 16:24
0

Your code

union {
  struct {
    float x;
    float y;
    float z;
  };
  float v[3];
};

is like

union Foo {
   int;
   float v[3];
};

which is surely invalid (in C99 and before).

The reason is probably to simplify parsing (in C), because in that case you only need to check that the struct/union body has only "declarator statements" like

Type field;

That said, gcc and "other compilers" supports unnamed fields as an extension.

Edit: Anonymous structs are now officially supported in C11 (§6.7.2.1/13).

kennytm
  • 510,854
  • 105
  • 1,084
  • 1,005
  • 5
    From a parsing perspective, i don't think that `union { ... }` is any different than `struct { ... }`. The former is valid, but the latter is not. – Johannes Schaub - litb Feb 12 '10 at 22:19
  • 3
    Given how absurdly difficult C++ is to parse in general, I doubt the standard committed disallowed unnamed structs and unions just to simplify parsing. – Adrian McCarthy Feb 13 '10 at 00:28
  • @Adrian: I said C, not C++. C++ adopts C's syntax and extend it. Probably C++'s creators don't see a need to allow unnamed struct/union members so they don't mess with that part of syntax. – kennytm Feb 13 '10 at 05:32
  • 1
    @Adrian, Good point there Adrian, I always didn't think "too hard to implement" would ever be a concern of Bjarne and crew – bobobobo Jun 07 '10 at 21:15
  • C and C++ both support unnamed unions, so the comment that `union { ... };` is invalid is not correct. – bames53 Oct 08 '12 at 16:10
  • @bobobobo difficulty of implementation affects many things in the C++ standard. For example, the places which say 'no diagnostic required' typically include that because detecting whatever error condition is being discussed is too difficult or impossible to implement in the general case. – bames53 Oct 08 '12 at 16:15
  • @bames53: C99 did not support unnamed struct fields. C11 does (edited the post to show that.) I don't think C++11 support unnamed struct field. – kennytm Oct 08 '12 at 16:31
  • Correct, C++11 does not support anonymous structs, but does support anonymous unions. C99 is the same. C11 additionally supports anonymous structs. C11 does not _add_ support for anonymous unions, because they were already supported in C99. – bames53 Oct 08 '12 at 16:36
-2

Edit: I put up a non-answer since I didn't realize the difference between an "anonymous struct" and an "unnamed struct". Rather than delete this answer, I will just leave it up, but my response here is not correct.

Original response follows:


I don't see it mentioned in any of the answers here, I guess since they're mostly written from before the "modern C++" era, but since I found my way here via a google search on "C++ anonymous struct", I'll just put this answer down here:

I'm able to do the following:

struct /* no typename */
{
    int i=2;
} g_some_object{};

int main()
{
    return g_some_object.i;
}

I noticed this behavior is actually leveraged in some of the examples for C++20 coroutines on cppreference, particularly for demonstrating a task awaiter.

If at any point in the past this behavior was not allowed, then that's no longer the case--we can definitely do this now.

  • 1
    You are using an _unnamed_ `struct`. These have always been legal; they're just a structure that doesn't have a type name, but they have an instance which is of that type. The question is about _anonymous_ `struct`s which have no type name _and_ no instance created -- which is what is in the question's example. – Human-Compiler Jul 01 '22 at 18:37