2011-02-25 8 views
3

명시 적 구조체 레이아웃과 구조체 오버레이를 이해하려고하는데 예상 한 동작이 보이지 않습니다.FieldOffset 예기치 않은 동작을 사용하는 구조체

IntField1 : 1
IntField2 : 2
CharArray : ABCDEF
SomeByte : 1
내가 좋아하는 뭔가가 수 있도록이에서 결과를 기대

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

: 아래의 코드 감안할 때 하위 구조 :
{CharArray1 : ABCDEF
CharArray2 : ABCD
CharArray3 : E}

하지만 결과는 다음

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

왜 TestStruct의 CharArray의 길이는 4입니까? 나는 6 문자 ABCDEF를 가지고 그것을 epxected지만 그것은 ABCD만을 포함합니다. TestStruct2.CharArray1과 동일합니다.

+0

이 게시물을 도움이되었습니다. http://m.developerfusion.com/article/84519/mastering-structs-in-c/ – SwDevMan81

+0

Thanks. 나는 그것을 실제로 읽었고 아직도 내가 무엇을보고 있는지 이해하지 못한다. 아마도 나는 다시 조금 더 가까이 읽을 필요가있다. – Domc

답변

2

TestStruct2를 CharArray 뒤에 넣지만 같은 오프셋으로 놓으면 이제 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이 6 자 깁니다.

+0

wow very interesting!그 일이 일어난 이유를 이해하는 것이 좋다. 그래도 고마워. – Domc

+0

메모리가 겹쳐져 있기 때문에 동일한 메모리 위치 (8:11 오프셋)에서 2 가지 (실제로는 3 가지) 다른 크기, 크기 4의 배열 및 크기 6의 [2] 배열 [ CharArray2의 길이를 변경하면 다른 문자도 변경됩니다. –

0

C#의 char은 2 바이트의 유니 코드 문자입니다.

비록 거기에 substruct를 유지하면서 예상 한 결과를 얻을 수는 없지만. 겹쳐지는 SizeConst 배열은 물건을 엉망으로 만드는 것처럼 보입니다.

2

char []는 참조 유형이며, 그 크기는 하나의 IntPtr이며 플랫폼 (x86 또는 x64) 및 해당 값이 구조의 내부에 저장되지 않은 경우 4 또는 8 바이트가 될 수 있습니다.

MarshalAs 특성은 정보가 구조체 내에 저장되는 방식을 변경하지 않으며 구조체가 비 관리 코드에서 /로 변환되는 방식 만 변경합니다.