If you are wanting to place structs within other structs which are themselves Layoutind.Explict you should Use an explicit Size value (in bytes) if you expect them to work in different bitness modes (or on machines with different packing requirements)
What you are saying there is "lay things out sequentially and don't pack internally but use as much space as you like at the end".
If you do not specify Size the runtime is free to add as much space as it likes.
The reason it in general refuses to let structs and object types overlap is that the GC routine must be free to traverse the live object graph. While doing this it cannot know if a unioned (overlapping) field is meaningful as an object reference or as raw bits (say an int or a float). Since it must traverse all live object references to behave correctly it would end up traversing 'random' bits which might point anywhere in the heap (or out of it) as if they were references before you know it you're General Protection Faulting.
Since 32/64 references will take up 32 or 64 bits according to the runtime you must use Explict, only union references with references and value types with value types, ensure your reference types are aligned to the boundaries of both target platforms if they differ (Note: Runtime dependent see below) and do one of the following:
- Ensure that all reference fields are the last entry in the struct - it is then free to make the struct bigger/smaller depending on the bitness of the runtime environment.
- Force all object references to consume 64bits whether you are on a 32 or 64bit environment
Note on alignment:
Apologies
I was in error on the unaligned reference fields - the compiler removed the type load unless I performed some action with the struct.
[StructLayout(LayoutKind.Explicit)]
public struct Foo
{
[FieldOffset(0)]
public byte padding;
[FieldOffset(1)]
public string InvalidReference;
}
public static void RunSnippet()
{
Foo foo;
foo.padding = 0;
foo.ValidReference = "blah";
// Console.WriteLine(foo); // uncomment this to fail
}
The relevant details are in the ECMA specification http://www.ecma-international.org/publications/files/ECMA-ST/Ecma-335.pdf see section 16.6.2 which mandates the alignment of native size values including &. It notes that the unaligned prefix instruction exists to work round this if required.
On mono however (both OSX intel and Win32 intel 32 bit) the above code works. Either the runtime does not respect the layouts and silently 'correct' things or it allows arbitrary alignment (historically they were less flexible than the MS runtime in this regard which is surprising).
The CLI intermediate form generated by mono does not include any .unaligned instruction prefixes, as such it appears to not conform to the spec.
That'll teach me to only check on mono.