Strange issue with LayoutKind.Explicit
-
Monday, February 04, 2008 12:12 PMHello,
I created an explicit structure as below:
Code Snippet: Version A[StructLayout(LayoutKind.Explicit)]
public struct ExplicitStruct
{
[FieldOffset(0)]
public short mShort;
[FieldOffset(2)]
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 6)]
public byte[] mByteArray;
[FieldOffset(8)]
public long mLong;
}
IMHO, this should work perfectly.
But when I use the above structure, I get type load exception saying "because it contains an object field at offset 2 that is incorrectly aligned or overlapped by a non-object field."
I tried many things and finally came up with the below structure:
and now it works fine.Code Snippet: Version B[StructLayout(LayoutKind.Explicit)]
public struct ExplicitStruct
{
[FieldOffset(0)]
public short mShort;//notice the change in offset
[FieldOffset(4)]
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 6)]
public byte[] mByteArray;
[FieldOffset(10)]
public long mLong;
}
My question is: Why do I need to start my byte array from offset '4', when a short type takes only 2 bytes. So what happens to the next two bytes (byte 3 and byte 4) after the short?
Regards,
Jayanta
Answers
-
Wednesday, February 06, 2008 6:23 AM
Jayanta Dey wrote: Hello,
I created an explicit structure as below:
Code Snippet: Version A[StructLayout(LayoutKind.Explicit)]
public struct ExplicitStruct
{
[FieldOffset(0)]
public short mShort;
[FieldOffset(2)]
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 6)]
public byte[] mByteArray;
[FieldOffset(8)]
public long mLong;
}
IMHO, this should work perfectly.
But when I use the above structure, I get type load exception saying "because it contains an object field at offset 2 that is incorrectly aligned or overlapped by a non-object field."
I tried many things and finally came up with the below structure:
and now it works fine.Code Snippet: Version B[StructLayout(LayoutKind.Explicit)]
public struct ExplicitStruct
{
[FieldOffset(0)]
public short mShort;//notice the change in offset
[FieldOffset(4)]
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 6)]
public byte[] mByteArray;
[FieldOffset(10)]
public long mLong;
}
My question is: Why do I need to start my byte array from offset '4', when a short type takes only 2 bytes. So what happens to the next two bytes (byte 3 and byte 4) after the short?
Regards,
JayantaOK. I think I understand what's going on here. It seems like the problem is related to the fact that the array type (which is an object type) must be stored at a 4-byte boundary in memory. However, what you're really trying to do is serialize the 6 bytes separately.
I think the problem is the mix between FieldOffset and serialization rules. I'm thinking that structlayout.sequential may work for you, since it doesn't actually modify the in-memory representation of the structure. I think FieldOffset is actually modifying the in-memory layout of the type. This causes problems because the .NET framework requires object references to be aligned on appropriate boundaries (it seems).
-
Wednesday, February 06, 2008 6:38 AM
The default behaviour in the framework is for values in the structure to be aligned at 4-byte boundaries, so values start at FieldOffset 0,4,8,12 ...
Values that are smaller than 4 bytes (your short for example) get padded up to 4 bytes.
You might have seen people use
StructLayout(LayoutKind.Explicit, Pack:=1)
This tells the framework to pack everything in to 1 byte boundaries, so there will be no padding.
All Replies
-
Wednesday, February 06, 2008 6:23 AM
Jayanta Dey wrote: Hello,
I created an explicit structure as below:
Code Snippet: Version A[StructLayout(LayoutKind.Explicit)]
public struct ExplicitStruct
{
[FieldOffset(0)]
public short mShort;
[FieldOffset(2)]
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 6)]
public byte[] mByteArray;
[FieldOffset(8)]
public long mLong;
}
IMHO, this should work perfectly.
But when I use the above structure, I get type load exception saying "because it contains an object field at offset 2 that is incorrectly aligned or overlapped by a non-object field."
I tried many things and finally came up with the below structure:
and now it works fine.Code Snippet: Version B[StructLayout(LayoutKind.Explicit)]
public struct ExplicitStruct
{
[FieldOffset(0)]
public short mShort;//notice the change in offset
[FieldOffset(4)]
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 6)]
public byte[] mByteArray;
[FieldOffset(10)]
public long mLong;
}
My question is: Why do I need to start my byte array from offset '4', when a short type takes only 2 bytes. So what happens to the next two bytes (byte 3 and byte 4) after the short?
Regards,
JayantaOK. I think I understand what's going on here. It seems like the problem is related to the fact that the array type (which is an object type) must be stored at a 4-byte boundary in memory. However, what you're really trying to do is serialize the 6 bytes separately.
I think the problem is the mix between FieldOffset and serialization rules. I'm thinking that structlayout.sequential may work for you, since it doesn't actually modify the in-memory representation of the structure. I think FieldOffset is actually modifying the in-memory layout of the type. This causes problems because the .NET framework requires object references to be aligned on appropriate boundaries (it seems).
-
Wednesday, February 06, 2008 6:38 AM
The default behaviour in the framework is for values in the structure to be aligned at 4-byte boundaries, so values start at FieldOffset 0,4,8,12 ...
Values that are smaller than 4 bytes (your short for example) get padded up to 4 bytes.
You might have seen people use
StructLayout(LayoutKind.Explicit, Pack:=1)
This tells the framework to pack everything in to 1 byte boundaries, so there will be no padding. -
Friday, February 08, 2008 3:04 AMModeratorThe Pack field should be used when the LayoutKind.Sequential value is specified.
-
Friday, February 08, 2008 11:18 AM
Thanks people!
Ok, I understand what you guys are saying and you are right the offset has to be a multiple of 4 and I cannot use pack in explicit layout.
Here is the situation, I have a union in C, which I want to map in C# (for marshalling). The C union is actually a union of two C structures with different data types (integers, shorts, char[], wchar_t[] with varying array sizes).
So I am finding it difficult to map such a complex structure in C#. I believe to map a C union, I have to use explicit layout, but that offset padding (multiple of 4) is preventing me from creating an exact mapping.
Any help in this regard will be very helpful.
Regards,
Jayanta
-
Saturday, February 09, 2008 12:51 PMModeratorNot any kind of C structure can be exactly converted to a C# equivlent class. But there's a tool may be able to help you:
P/Invoke Interop Assistant
Thanks!

