In the following code I build a pointer to a struct located at an arbitrary memory location:
[StructLayout(LayoutKind.Explicit)]
public struct S
{
[FieldOffset(0)] int f0;
[FieldOffset(4)] int f4;
public static void Main() {
unsafe {
S* rawPtr = (S*)0x1234;
rawPtr->f0 = 42;
}
}
}
If I change f4
's type to object
instead of int
, I get the error Compiler Error CS0208: Cannot take the address of, get the size of, or declare a pointer to a managed type ('type').
What are the constaints on struct S
that allow building pointers on that type, at the CIL
(not just C#
) level?
This page on MSDN says sbyte
, byte
, short
, ushort
, int
, uint
, long
, ulong
, char
, float
, double
, decimal
, bool
, enums and pointers are allowed, as well as "user-defined struct type that contains fields of unmanaged types only", but doesn't specify what an unmanaged type is.
I could not find an easily navigable version of ECMA-335 online, but ECMA-334 paragraph 27.2 says:
An unmanaged-type is any type that isn’t a reference-type, a type-parameter, or a generic struct-type and contains no fields whose type is not an unmanaged-type. In other words, an unmanaged-type is one of the following:
sbyte
,byte
,short
,ushort
,int
,uint
,long
,ulong
,char
,float
,double
,decimal
, orbool
.Any enum-type.
Any pointer-type.
Any non-generic user-defined struct-type that contains fields of unmanaged-types only.
[Note: Constructed types and type-parameters are never unmanaged-types. end note]
The packing mode of a structure does not seem to be relevant to this distinction.