Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

structs using FieldOffset unexpected behaviour

I am trying to understand explicit struct layout and struct overlaying and i am not seeing behaviour i expect. Given the code below:

class Program
{

    static void Main(string[] args)
    {
        byte[] bytes = new byte[17];
        bytes[0] = 0x01; // Age is 1    //IntField1
        bytes[1] = 0x00;                //IntField1
        bytes[2] = 0x00;                //IntField1
        bytes[3] = 0x00;                //IntField1
        bytes[4] = 0x02;                //IntField2
        bytes[5] = 0x00;                //IntField2
        bytes[6] = 0x00;                //IntField2
        bytes[7] = 0x00;                //IntField2

        bytes[8] = 0x41;                //CharArray A
        bytes[9] = 0x42;                //CharArray B
        bytes[10] = 0x43;               //CharArray C
        bytes[11] = 0x44;               //CharArray D

        bytes[12] = 0x45;               //CharArray E

        bytes[13] = 0x46;               //CharArray F
        bytes[14] = 0x00; // \0 decimal 0
        bytes[15] = 0x00; // \0 decimal 0
        bytes[16] = 0x01; // 1 decimal 1
        Console.WriteLine(Marshal.SizeOf(typeof(TestStruct)));

        TestStruct testStruct2 = (TestStruct) RawDeserialize(bytes, 0, typeof (TestStruct));

        Console.WriteLine(testStruct2);
        Console.ReadLine();
    }
    public static object RawDeserialize( byte[] rawData, int position, Type anyType )
    {
        int rawsize = Marshal.SizeOf( anyType );
        if( rawsize > rawData.Length )
            return null;

        IntPtr buffer = Marshal.AllocHGlobal( rawsize );
        Marshal.Copy( rawData, position, buffer, rawsize );
        object retobj = Marshal.PtrToStructure( buffer, anyType );
        Marshal.FreeHGlobal( buffer );
        return retobj;
    }
}

[StructLayout(LayoutKind.Explicit, Pack = 1)]
public struct TestStruct
{
    [FieldOffset(0)]
    public int IntField1;
    [FieldOffset(4)]
    public int IntField2;
    [FieldOffset(8)]
    [MarshalAs(UnmanagedType.ByValArray, SizeConst = 6)]
    public char[] CharArray;
    [FieldOffset(16)]
    public byte SomeByte;        

    [FieldOffset(8)]
    public TestStruct2 SubStruct;

    public override string ToString()
    {
        return string.Format("IntField1: {0}\nIntField2: {1}\nCharArray: {2}\nSomeByte: {3}\nSubStruct:\n{{{4}}}", 
            IntField1, IntField2,  new string(CharArray), SomeByte, SubStruct);
    }
}

[StructLayout(LayoutKind.Explicit, Pack = 1)]
public struct TestStruct2
{
    [FieldOffset(0)]
    [MarshalAs(UnmanagedType.ByValArray, SizeConst = 6)]
    public char[] CharArray1;
    [FieldOffset(0)]
    [MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)]
    public char[] CharArray2;
    [FieldOffset(4)]
    [MarshalAs(UnmanagedType.ByValArray, SizeConst = 2)]
    public char[] CharArray3;

    public override string ToString()
    {
        return string.Format("CharArray1: {0}\nCharArray2: {1}\nCharArray3: {2}",
           new string(CharArray1), new string(CharArray2), new string(CharArray3));
    }
}

I would expect the result from this to be something like:

IntField1: 1
IntField2: 2
CharArray: ABCDEF
SomeByte: 1
SubStruct:
{CharArray1: ABCDEF
CharArray2: ABCD
CharArray3: E }

but the result is:

IntField1: 1
IntField2: 2
CharArray: ABCD
SomeByte: 1
SubStruct:
{CharArray1: ABCD
CharArray2: ABCD
CharArray3: EF}

Why does the CharArray in the TestStruct have a length of 4? I epxected it to have 6 characters ABCDEF but it only contains ABCD. Same for the TestStruct2.CharArray1.

like image 530
Domc Avatar asked May 22 '26 18:05

Domc


1 Answers

char[] is a reference type, its size is one IntPtr, which can be 4 or 8 Bytes - depending on platform (x86 or x64) and its value in not stored inplace within the structure.

The MarshalAs attribute does not change how the information is stored within the struct, only how it is translated (e.g. to/from unmanaged code).

like image 62
Danny Varod Avatar answered May 25 '26 06:05

Danny Varod



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!