c++visual-c++flexible-array-memberanonymous-struct

MSVC struct layout changes when wrapping flexible array in anonymous struct?


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?


Solution

  • 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.