You are on page 1of 18

Anonymous and unamed struct : cpp


r/cpp
r/cpp

Posts 
 Search Reddit Open Gift


 Posted by u/jube_dev 3 years ago
44 
Anonymous and unamed struct

In the past, I wanted to do something like this:

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

It worked well, I was quite happy until I noticed a warning of the compiler saying that this was an
extension. More precisely, the standard says: "[Note: Nested types, anonymous unions, and functions
cannot be declared within an anonymous union. — end note]".

More recently, I wrote something like this:

enum class ShapeType {


Circle,
Rectangle,
};

struct Shape {
ShapeType type;

union {
struct {
float radius;
} circle;
struct {
float width;

Anonymous and unamed struct _ cpp.html[2/7/2022 12:33:18 PM]


Anonymous and unamed struct : cpp

float height;
} rectangle;
};
};

Again, a warning. Note that the two examples differ a bit. In the latter, there is an unnamed struct , i.e.
the type has no name, but the object has. In the former, there is an "anonymous struct", i.e. the type has
no name and the object has no name (the standard use "anonymous union" with this same definition).

Also note that this code compiles fine on GCC, Clang and MSVC when extensions are active. So here we
have a very good example of a feature that should be in the standard and that is not, with previous
experience and implementation in many compilers. Why does it compile? Because, C11 introduced
anonymous struct . Here is the definition (6.7.2.1): "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."

So, here it comes. I would like to propose a paper to introduce anonymous structures and relax the
constraints of what can be put inside an anonymous union so that these two snippets could be standard. I
am not a native speaker, and this is the first time I write a paper. So I would like to find a mentor and/or a
co-author for this task, someone with more experience in the process. Anyone interested?

 24 Comments

 Award

 Share

Comment as kinjalkishor

Comment
Comment
What are your thoughts?

      
Markdown Mode

   

Sort By: Best

Anonymous and unamed struct _ cpp.html[2/7/2022 12:33:18 PM]


Anonymous and unamed struct : cpp

manni66
· 3 yr. ago

And you want to write x,y,z into your Vector3 and then read the values as v[i]? Isn't that UB?


25


 Reply Give Award

Share
Share

Report
Report Save Follow
Follow

enchanted_mango_
· 3 yr. ago

It is UB (type punning), but it shouldn't be. It's kinda the point of their post I guess. It's just another thing
which is very, very useful in game programming but only "okay" because there are extensions for it.


36


 Reply Give Award
Give Award

Share

Report
Report Save
Save Follow

jube_dev
OP · 3 yr. ago

In some case, it is not. The standard says: "[Note: One special guarantee is made in order to simplify
the use of unions: If a standard-layout union contains several standard-layout structs that share a
common initial sequence (12.2), and if a non-static data member of an object of this standard-layout
union type is active and is one of the standard-layout structs, it is permitted to inspect the common
initial sequence of any of the standard-layout struct members; see 12.2. — end note ]"

This condition may be relaxed if we consider that float v[3] has the same layout than a struct with
three floats. In that case, the code would not be UB.


13

Anonymous and unamed struct _ cpp.html[2/7/2022 12:33:18 PM]


Anonymous and unamed struct : cpp

 Reply Give Award

Share
Share

Report
Report Save Follow
Follow

konanTheBarbar
· 3 yr. ago

I actually wanted to know this in detail once... while this is allowed by the C-standard, it is actually
still UB for the C++ standard. float v[3] and float,float,float do not share a common initial sequence
(by the wording of the c++ standard). While every compiler will just do the right thing, it is currently
still not covered by the standard.


26


 Reply Give Award
Give

Share
Share

Report
Report Save
Save Follow
Follow

jbakamovic
· 3 yr. ago
Cxxd

float v[3] and float,float,float do not share a common initial sequence

What does this exactly mean?


5


 Reply Give Award
Give Award

Share
Share

Report
Report Save
Save Follow
Follow

jube_dev
OP · 3 yr. ago

"The common initial sequence of two standard-layout struct types is the longest sequence of
non-static data members and bit-fields in declaration order,"

Anonymous and unamed struct _ cpp.html[2/7/2022 12:33:18 PM]


Anonymous and unamed struct : cpp

So it deals with structs only and not with arrays.


15


 Reply Give Award
Give Award

Share

Report
Report Save
Save Follow

Supadoplex
· 3 yr. ago · edited 3 yr. ago

This condition may be relaxed if we consider that float v[3] has the same layout than a struct
with three floats. In that case, the code would not be UB.

Do you mean that standard could be relaxed, so that there would not be UB, or that there wouldn't
be UB if the layout is the same, given the current standard?

I don't think there's a guarantee for the latter unless the standard is changed.


3


 Reply Give
Give Award

Share
Share

Report
Report Save
Save Follow
Follow

jube_dev
OP · 3 yr. ago

I agree with you, I meant the standard must be changed to guarantee this behavior.


3


 Reply Give
Give Award
Award

Share
Share

Report
Report Save
Save Follow
Follow

Anonymous and unamed struct _ cpp.html[2/7/2022 12:33:18 PM]


Anonymous and unamed struct : cpp

jpan127
· 3 yr. ago

I forgot where I read it and someone correct me if I am wrong, but I think the standard defines it as UB
but major compilers like GCC implement it as defined and allowed behavior since it is so useful / widely
used.


11


 Reply Give
Give Award
Award

Share

Report
Report Save
Save Follow

khedoros
· 3 yr. ago

That's the conclusion I came to last time I looked into it. The standard doesn't define the behavior, but
most compilers do. I use type-punning fairly often while doing game and emulator development.


1


 Reply Give Award

Share
Share

Report
Report Save Follow
Follow

ShillingAintEZ
· 3 yr. ago

You can always add an assert that the structure as a whole is 12 bytes. It is enormously useful and seems
to work with all major compilers.


0


 Reply Give
Give Award
Award

Share

Report Save Follow

Anonymous and unamed struct _ cpp.html[2/7/2022 12:33:18 PM]


Anonymous and unamed struct : cpp

Report Save Follow

Supadoplex
· 3 yr. ago · edited 3 yr. ago

Again, a warning.

What compiler warned about the latter program? Unnamed (but indeed not anonymous) structs are standard
conformant as far as I know, so the warning seems uncalled for.

Edit:

msvc /Wall: no warning


g++ -pedantic: no warning
icc -pedantic: no warning
clang++ -pedantic: yes warning. Talks about anonymous types inside anonymous union although the
type inside the union isn't anonymous. Might be a Clang bug.
Why does it compile? Because, C11 introduced anonymous struct.

Some compilers did support anonymous structs as an extension before C11 standardised them.

I would certainly like to see anonymous classes added to C++.


7


 Reply Give Award

Share
Share

Report
Report Save Follow
Follow

jube_dev
OP · 3 yr. ago

What compiler warned about the latter program?

Clang says: "warning: anonymous types declared in an anonymous union are an extension [-Wnested-
anon-types]"

Unnamed (but indeed not anonymous) structs are standard conformant as far as I know, so the
warning seems uncalled for.

Per what I cited in the post, I think it is considered a nested type and is thus forbidden.

Anonymous and unamed struct _ cpp.html[2/7/2022 12:33:18 PM]


Anonymous and unamed struct : cpp


3


 Reply Give Award
Give Award

Share

Report
Report Save
Save Follow

Supadoplex
· 3 yr. ago

Per what I cited in the post, I think it is considered a nested type and is thus forbidden.

At least the warning message is misleading in that case.

You're citing a note. Notes shall not contain requirements and are not normative. The wording of the
note does seem to strongly imply that this is the case, but I would like to see the rule that actually says
so.


3


 Reply Give Award

Share
Share

Report
Report Save Follow
Follow

Deaod
· 3 yr. ago

The sentence immediately before that note is the following: "Each member-declaration in the
member-specification of an anonymous union shall either define a non-static data member or be a
static_assert-declaration."

Basically, the standard gives a whitelist of stuff you can define, and the note specifies what you can
not define.

The standard later goes on to explicitly list a few more things: "An anonymous union shall not have
private or protected members ([class.access]). An anonymous union shall not have member
functions."


3

Anonymous and unamed struct _ cpp.html[2/7/2022 12:33:18 PM]


Anonymous and unamed struct : cpp

 Reply Give Award


Give

Share
Share

Report
Report Save
Save Follow
Follow

Supadoplex
· 3 yr. ago

An unnamed struct definition does define a non-static data member though, so the wording
seems ambiguous to me. Perhaps that's why the compilers fail to agree as well.


1


 Reply Give Award
Give Award

Share
Share

Report
Report Save
Save Follow
Follow

Deaod
· 3 yr. ago

It defines two things: A non-static data member of an unnamed struct type, and an unnamed
struct.


1


 Reply Give Award
Give Award

Share

Report
Report Save
Save Follow

Comment deleted by user · 3 yr. ago

degski
· 3 yr. ago · edited 3 yr. ago

Anonymous and unamed struct _ cpp.html[2/7/2022 12:33:18 PM]


Anonymous and unamed struct : cpp

I'm happy I don't use unamed structs, sounds terrible.

But on a serious note, yes, this should be un-UB'ed, certainly as C11 explicitly allows it [apparently].

PS: I think, generically, C++ should strive to be a super-set of C, this will keep everybody sane and there is no
reason whatsoever that what works in C cannot work in C++. In the worst case we should have an attribute [[
c_language ]], in a similar way as Rust has unsafe C++ bits. This then immediately makes all compliant C++
compilers C compliant, only MSVC needs some work.


4


 Reply Give Award

Share
Share

Report
Report Save Follow
Follow

tangerinelion
· 3 yr. ago

What's wrong with a class that defines x, y, z methods and operator[] and stores an array internally? I work on
CAD software and that's literally what we do. Force it to be inline if the function calls are too slow.


7


 Reply Give Award

Share
Share

Report
Report Save Follow
Follow

TheoreticalDumbass
· 3 yr. ago

vec.x() seems less pretty than vec.x, especially in vec.x() = 123 example.


6


 Reply Give Award
Give Award

Share

Report Save Follow

Anonymous and unamed struct _ cpp.html[2/7/2022 12:33:18 PM]


Anonymous and unamed struct : cpp

Report Save Follow

Tyg13
· 3 yr. ago · edited 3 yr. ago

could do something like

struct Vector {
Vector(float x, float y, float z) : v{x, y, z} {}
float v[3];
float& x = v[0];
float& y = v[1];
float& z = v[2];
};


1


 Reply Give Award

Share
Share

Report
Report Save Follow
Follow

TheoreticalDumbass
· 3 yr. ago

Your Vector is a lot larger than the author Vector3 struct, sizeof(Vector) = 40, while sizeof(Vector3) =
12.


1


 Reply Give Award
Give

Share
Share

Report
Report Save
Save Follow
Follow

Tyg13
· 3 yr. ago

Ah, true.

Anonymous and unamed struct _ cpp.html[2/7/2022 12:33:18 PM]


Anonymous and unamed struct : cpp


1


 Reply Give Award
Give Award

Share
Share

Report
Report Save
Save Follow
Follow

Comment deleted by user · 3 yr. ago

OrangeGirl_
· 3 yr. ago

To not get UB, this code provides the same interface at the cost of extra overhead:

struct Vector3 {
Vector3() : data(), x(data[0]), y(data[1]), z(data[2]) {}
float& operator[](std::size_t i)
{
return data[i];
}
const float& operator[](std::size_t i) const
{
return data[i];
}
float data[3];
float& x;
float& y;
float& z;
};

enum class ShapeType {


Circle,
Rectangle
};

struct Shape {
Shape() : data(), radius(data[0]), width(data[0]), height(data[1]) {}
ShapeType type;

Anonymous and unamed struct _ cpp.html[2/7/2022 12:33:18 PM]


Anonymous and unamed struct : cpp

float data[2];
float& radius;
float& width;
float& height;
};


2


 Reply Give Award

Share
Share

Report
Report Save Follow
Follow

Nobody_1707
· 3 yr. ago

Can't you do the same thing without the overhead like so:

struct Vector3 {
float x, y, z;

constexpr auto operator[](std::ptrdiff_t i) noexcept -> float& {


switch(i) {
case 0: return x;
case 1: return y;
case 2: return z;
}
std::terminate();
}
constexpr auto operator[](std::ptrdiff_t i) const noexcept
-> float const& {
switch(i) {
case 0: return x;
case 1: return y;
case 2: return z;
}
std::terminate();
}
};

Also, operator[] really should take a ptrdiff_t , since that's what it takes on actual arrays.

Anonymous and unamed struct _ cpp.html[2/7/2022 12:33:18 PM]


Anonymous and unamed struct : cpp


1


 Reply Give Award
Give Award

Share

Report
Report Save
Save Follow

Supadoplex
· 3 yr. ago

The point of having an array is not so that you get operator[] . The need for the array is usually so
that you can have a pointer to x, and increment it to get y (without relying on UB).


3


 Reply Give Award

Share
Share

Report
Report Save Follow
Follow

Nobody_1707
· 3 yr. ago

Oh. Yeah, that makes sense. They really need to standardize on the way C11 handles this. That's
one of the few things that C got right that C++ didn't.


1


 Reply Give
Give Award

Share
Share

Report
Report Save
Save Follow
Follow

remotion4d
· 3 yr. ago

https://github.com/google/mathfu/blob/master/include/mathfu/internal/vector_3.h#L184

Anonymous and unamed struct _ cpp.html[2/7/2022 12:33:18 PM]


Anonymous and unamed struct : cpp


2


 Reply Give Award

Share
Share

Report
Report Save Follow
Follow

sumo952
· 3 yr. ago

So this library is basically UB? And even silences the warnings?

And isn't the same true for glm, which is quite widely used?


8


 Reply Give
Give Award
Award

Share

Report
Report Save
Save Follow

remotion4d
· 3 yr. ago

The point is that there are a lot of libraries that do this and every compiler that I know support this.


2


 Reply Give Award

Share
Share

Report
Report Save Follow
Follow

e_man604
· 3 yr. ago

I even Saw this in a game dev Book and a guide for SIMD/SSE programming. I've been looking into it this
last week and just am confused.

Anonymous and unamed struct _ cpp.html[2/7/2022 12:33:18 PM]


Anonymous and unamed struct : cpp

What's the usecase of union if it's undefined behaviour? Or is it just because it's an inherited feature of c
and should be skipped in c++?


2


 Reply Give Award
Give Award

Share

Report
Report Save
Save Follow

Supadoplex
· 3 yr. ago · edited 3 yr. ago

Union isn't "undefined behaviour" in general.

The purpose of union is to use a single area of memory for a (member) variable whose type is chosen
at runtime, but the choice is limited to a set of types. A typical use case is for example parsing a JSON
object: You cannot know at compile time whether the next element you read is going to be a string,
integer , array ... so when you parse the input into a data structure, you can specify a type that can hold
any one of those without allocating space for all possible types spearately.

For this use case, there is little use for union since C++17 added std::variant , which provides you
with safer, easier to use interface for the same thing. Having union in C++ is still important for
compatibility with C of course.

Trying to use union for type-punning or array indexing is undefined in standard C++. The C language -
unlike C++ - has been changed to allow these uses of union in C99 standard version. These may also
be supported by some C++ compilers as a language extension.


3


 Reply Give Award

Share
Share

Report
Report Save Follow
Follow

ShillingAintEZ
· 3 yr. ago

You can start with a union as the outside and put structs on the inside. You can then make one for x, y, z one
for float[3], one for r,g,b etc.

Anonymous and unamed struct _ cpp.html[2/7/2022 12:33:18 PM]


Anonymous and unamed struct : cpp


0


 Reply Give Award

Share
Share

Report
Report Save Follow
Follow

jube_dev
OP · 3 yr. ago

If you mean:

union Vector3 {
struct {
float x;
float y;
float z;
};
struct {
float r;
float g;
float b;
};
float v[3];
};

then you have the same warnings.

The only solution (but you loose the array):

struct Vector3 {
union { float x; float r; };
union { float y; float g; };
union { float z; float b; };
};


3


 Reply Give Award
Give Award

Share

Anonymous and unamed struct _ cpp.html[2/7/2022 12:33:18 PM]


Anonymous and unamed struct : cpp

Report
Report Save
Save Follow

ShillingAintEZ
· 3 yr. ago

Anonymous and unamed struct _ cpp.html[2/7/2022 12:33:18 PM]

You might also like