2012-11-05 35 views
5

मैं है निम्नलिखित संरचनाMarshal.SizeOf संरचना, अत्यधिक संख्या

[StructLayout(LayoutKind.Sequential)] 
public struct SFHeader 
{ 

    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 5)] 
    public string FileName; 

    public int Offset; 

    public short Size; 

    public byte Flags; 

    public byte Source; 


    public long LastWriteTime; 


    public byte[] GetBytes() 
    { 
     int size = Marshal.SizeOf(this); 
     var buffer = new byte[size]; 
     IntPtr ptr = Marshal.AllocHGlobal(size); 

     Marshal.StructureToPtr(this, ptr, true); 
     Marshal.Copy(ptr, buffer, 0, size); 
     Marshal.FreeHGlobal(ptr); 

     return buffer; 
    } 


    public static SFHeader FromBytes(byte[] buffer) 
    { 
     var str = new SFHeader(); 
     int size = Marshal.SizeOf(str); 

     IntPtr ptr = Marshal.AllocHGlobal(size); 
     Marshal.Copy(buffer, 0, ptr, size); 
     str = (SFHeader)Marshal.PtrToStructure(ptr, str.GetType()); 
     Marshal.FreeHGlobal(ptr); 

     return str; 
    } 

} 

मैं (सॉकेट के साथ पैकेट के रूप में भेजने के लिए) बाइट की एक सरणी के लिए अपने संरचना बदलने की आवश्यकता है, इसलिए मैं GetBytes विधि का उपयोग देता है लेकिन

  • फ़ाइल का नाम (स्ट्रिंग): यह 24 बाइट्स की एक सरणी के बजाय 21 बाइट्स की एक सरणी देता है 5 बाइट्स
  • ऑफसेट (int): 4 बाइट्स
  • +०१२३५१६४१०६
  • आकार (संक्षिप्त): 2 बाइट्स
  • झंडे (बाइट): 1 बाइट
  • स्रोत (बाइट): 1 बाइट
  • LastWriteTime (लंबी): 8 बाइट्स

तो: 5 4 + 2 + 1 + 1 + 8 = 21 बाइट्स।
ऐसा इसलिए होता है क्योंकि Marshal.SizeOf 24 लौटाता है, क्यों? और ऐसा लगता है कि अधिक में बाइट्स उदाहरण के लिए, स्ट्रिंग के बाइट्स के बाद रखा जाता है वास्तव में निम्नलिखित संरचना:

var header = new SFHeader() 
{ 
    FileName = "aaaa", 
    Offset = 1, 
    Size = 1 
}; 

निम्नलिखित बफर में बदल जाती है:

[0] = 97 
[1] = 97 
[2] = 97 
[3] = 97 
[4] = 0 
[5] = 0 
[6] = 0 
[7] = 0 
[8] = 1 
[9] = 0 
[10] = 0 
[11] = 0 
[12] = 1 
[13] = 0 
... The following are all zero (0) 

पांचवें , छठे और सातवें बाइट्स अतिरिक्त हैं। मैं इस समस्या को कैसे हल कर सकता हूं?

+0

स्ट्रिंग की अजीब लंबाई है, इसलिए अन्य फ़ील्ड को वास्तविकता मिली है। स्पष्ट लेआउट का उपयोग करके इसे ठीक किया जा सकता है। "अनुक्रमिक" का मतलब "संगत" नहीं है। – harold

+0

क्या स्ट्रिंग हमेशा एक ही लंबाई है? – SynerCoder

+0

@ सिनरकोडर हां, अधिकतम 5 बाइट्स। – Nick

उत्तर

7

आप बाइट-संरेखण समस्या में भाग रहे हैं। एक्सेस की गति के लिए शब्द सीमाओं पर फ़ील्ड रखने के प्रयास में, कंपाइलर आपके string को 3 अतिरिक्त बाइट्स के साथ पैडिंग कर रहा है। इसे ठीक करने के लिए, StructLayoutAttribute के Pack फ़ील्ड का उपयोग करें।

[StructLayout(LayoutKind.Sequential, Pack=1)] // notice the packing here 
public struct SFHeader 
{ 
    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 5)] 
    public string FileName; 

    public int Offset; 

    public short Size; 

    public byte Flags; 

    public byte Source; 

    public long LastWriteTime; 
} 
+0

यह सही है। यह पूरी तरह से काम करता है। धन्यवाद। – Nick

0

आप एक स्ट्रिंग के बजाय fixed size buffer का उपयोग कर सकते हैं।

[StructLayout(LayoutKind.Sequential)] 
public unsafe struct SFHeader 
{ 
    public fixed char FileName[5]; 
    public int Offset; 
    public short Size; 
    public byte Flags; 
    public byte Source; 
    public long LastWriteTime; 

    public byte[] GetBytes() 
    { 
     //omitted 
    } 

    public static SFHeader FromBytes(byte[] buffer) 
    { 
     //omitted 
    } 
} 
+0

ठीक है कि अजीब है, सवाल पहले से ही उत्तर दिया गया है ... – SynerCoder

+2

यह 32 का आकार देता है, 21 नहीं। यहां तक ​​कि यदि आप 'char'' को 'बाइट' से बदलते हैं, तो भी आपको 'मार्शल .इज़ऑफ()' कॉल से 24 मिलते हैं। –

+0

@ मातदाविस मेरी रक्षा में मैंने कभी भी structs के साथ बहुत कुछ नहीं किया: पी – SynerCoder