2011-02-25 55 views
3

我想了解顯式結構佈局和結構覆蓋,我沒有看到我期望的行爲。考慮下面的代碼:使用FieldOffset意外行爲的結構

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)); 
    } 
} 

我期望從這一結果是這樣的:

IntField1:1
IntField2:2
CharArray:ABCDEF
SomeByte:1
SubStruct:
{CharArray1:ABCDEF
CharArray2:ABCD
個CharArray3:電子}

但結果是:

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

爲什麼TestStruct中的CharArray的長度是4?我將它表示爲有6個字符ABCDEF,但它只包含ABCD。相同的TestStruct2.CharArray1。

+0

我發現這篇文章有幫助:http://m.developerfusion.com/article/84519/mastering-structs-in-c/ – SwDevMan81 2011-02-25 03:18:45

+0

謝謝。我實際上讀過這些,但仍然不明白我所看到的。也許我需要再讀一點更近...... – Domc 2011-02-25 03:22:14

回答

2

通過在CharArray之後放置TestStruct2,但在相同的偏移量處,現在指向TestStruct2的CharArray2的指針正在覆蓋曾經是TestStruct自己的chararray的指針。

如果您註釋掉或更改TestStruct2的CharArray2的長度,您將看到預期結果。

同樣看,當你把struct2首先發生了什麼,即:

[StructLayout(LayoutKind.Explicit, Pack = 1)] 
    public struct TestStruct 
    { 
     [FieldOffset(8)] 
     public TestStruct2 SubStruct; 

     [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;   


     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); 
     } 
    } 

現在的效果是相反的,並TestStruct2的CharArray2長六個字符。

+0

哇很有趣!善於理解發生的原因。謝謝你,雖然。 – Domc 2011-02-25 03:48:14

+0

因爲內存是重疊的:你試圖讓相同的內存位置(偏移8:11)指向兩個(實際上三個)不同的東西,一個大小爲4的數組和一個大小爲6的[2]數組如果你改變CharArray2的長度,你會看到其他的改變。 – 2011-02-25 03:55:52

0

要記住的一件事是C#中的char是2個一個字節的unicode字符。

雖然我仍然無法得到您的預期結果,同時保持子結構在那裏。重疊的SizeConst數組似乎弄糟了。

2

炭[]是引用類型,它的大小是一個IntPtr的,它可以是4或8個字節 - 取決於平臺(x86或x64),其值在不該結構內就地保存。

MarshalAs特性不改變的信息是如何存儲的結構內,它只是如何轉換(例如至/從非託管代碼)。