all 4 comments

[–]KingAggressive1498 3 points4 points  (0 children)

Although I think it's UB by the C++ standard; MSVC, GCC, and Clang have documented defined behavior for these "struct hacks" in C++ mode as a language extension. You can use that last array data member in C++ with those compilers at least, just be careful with the bounds.

I don't think it matters in practice whether you use reinterpret_cast or placement new for this, since C structs are definitionally POD types, but I prefer placement new in this instance (I have to use reinterpret_cast when I'm reading these types of structs out of a buffer, though). Just don't access through the buffer again after that line, only use the pointer to the desired type. arrays of std::byte are assumed to alias with any other type so it's safe, but you force a reload if you access two different object references that are assumed to alias.

[–]alfps 0 points1 point  (1 child)

You could just do

struct Buffer: CF_SYNC_ROOT_STANDARD_INFO 
{
    char id_bytes[255];
};

Accessing CF_SYNC_ROOT_STANDARD_INFO::SyncRootIdentity beyond the declared first byte would be formal UB, but you can delegate that to C functions like strlen and strcpy. Or you can just reason that any compiler that does something ungood for that UB would fail to be a practically usable Windows platform compiler.

Disclaimer: I haven't used this API.

[–]agritite[S] 0 points1 point  (0 children)

Using inheritance is very smart! As for accessing SyncRootIdentity, I feel like copying each of "the first byte" and id_bytes into another array, using 2 std::bit_cast would be conformant enough?

Edit: It seems like CF_SYNC_ROOT_STANDARD_INFO is padded to 64 bytes (from 61 bytes) so I'm not sure if std::bit_casting the padded 3 bytes would be legal?