I'm looking at layout info for the following structs using godbolt:
struct Foo1 {
int size;
void *data[];
};
struct Foo2 {
int size;
struct {
void *data[];
};
};
I'd expected the layout for both structs Foo1
and Foo2
to be the same. From what I understand, any fields of an anonymous nested struct are simply "folded" into the parent struct. So the layout of Foo2
should turn out the same as that of Foo1
.
However, the layouts generated by MSVC 19.16, and displayed when using the flag /d1reportSingleClassLayoutFoo
differ:
class Foo1 size(8):
+---
0 | size
| <alignment member> (size=4)
8 | data
+---
class Foo2 size(16):
+---
0 | size
| <alignment member> (size=4)
| <anonymous-tag> <alignment member> (size=8)
8 | data
| <alignment member> (size=7)
+---
Foo2
is double the size of Foo1
. And data
suddenly seems to have a size of 1 byte.
There are some warning generated with -Wall
:
warning C4200: nonstandard extension used: zero-sized array in struct/union
note: This member will be ignored by a defaulted constructor or copy/move assignment operator
warning C4820: 'Foo1': '4' bytes padding added after data member 'Foo1::size'
warning C4200: nonstandard extension used: zero-sized array in struct/union
note: This member will be ignored by a defaulted constructor or copy/move assignment operator
warning C4820: 'Foo2::<anonymous-tag>': '7' bytes padding added after data member 'Foo2::data'
warning C4201: nonstandard extension used: nameless struct/union
warning C4820: 'Foo2': '4' bytes padding added after data member 'Foo2::size'
But none of these seem to explain the difference in layout, or hint towards undefined behavior. And, neither does the doc: Anonymous structs.
For the record, I do know that this code is relying on MSVC extensions:
warning C4200: nonstandard extension used: zero-sized array in struct/union
warning C4201: nonstandard extension used: nameless struct/union
The "zero-sized array" data
seems to be a flexible array member, since putting it before the size
field throws an error.
Why do the layouts of Foo1
and Foo2
differ?
Your anonymous struct is a distinct type. As such, it cannot have a zero size, and therefore has a size of 1 byte. data
still has a zero size, but the struct that contains it does not.