Is there equivalent functionality to C# Structs/StructLayout with field offsets in C++?

Viewed 306

Take this example of a C# struct:

    [StructLayout(LayoutKind.Explicit)]
    public struct Example
    {
        [FieldOffset(0x10)]
        public IntPtr examplePtr;

        [FieldOffset(0x18)]
        public IntPtr examplePtr2;

        [FieldOffset(0x54)]
        public int exampleInt;
    }

I can take an array of bytes, and transform it to this struct like so:

    public static T GetStructure<T>(byte[] bytes)
    {
        var handle = GCHandle.Alloc(bytes, GCHandleType.Pinned);
        var structure = (T)Marshal.PtrToStructure(handle.AddrOfPinnedObject(), typeof(T));
        handle.Free();
        return structure;
    }

    public static T GetStructure<T>(byte[] bytes, int index)
    {
        var size = Marshal.SizeOf(typeof(T));
        var tmp = new byte[size];
        Array.Copy(bytes, index, tmp, 0, size);
        return GetStructure<T>(tmp);
    }

    GetStructure<Example>(arrayOfBytes);

Is there equivalent functionality in C++ to take an array of bytes and transform it to a struct, where not all bytes are used in the transformation (C# structlayout.explicit w/ field offsets)?

I don't want to do something like the following:

struct {
  pad_bytes[0x10];
  DWORD64 = examplePtr;
  DWORD64 = examplePtr2;
  pad_bytes2[0x44];
  int exampleInt;
}
1 Answers

No, I am not aware of a way to specify the byte offset of some struct member - there is definitely nothing in the standard, and I don't know of any compiler specific extension.

In addition to padding members (as you already mentioned), you can also use alignas, #pragma pack, and __declspec(align(#)) (on MSVC), and __attribute__ ((packed)) and __attribute__ ((aligned(#))) (on GCC). Of course these don't let you specify the offset, but they can help control the layout of your struct.

The best I can think of to ensure that your layout matches your expectations is using static_assert with offsetof:

struct Example{
  char pad_bytes[0x10];
  DWORD64 examplePtr;
  DWORD64 examplePtr2;
  char pad_bytes2[0x44];
  int exampleInt;
};
static_assert(offsetof(Example, examplePtr) == 0x10);
static_assert(offsetof(Example, examplePtr2) == 0x18);
static_assert(offsetof(Example, exampleInt) == 0x54);
Related