2012-11-05 12 views
5

ho la seguente strutturaMarshal.SizeOf struttura restituisce eccessivo numero

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

} 

devo convertire la struttura di una matrice di byte (per inviare come pacchetto con zoccolo), quindi utilizzare il metodo GetBytes, ma restituisce un array di 24 byte invece che una matrice di byte 21:

  • file (stringa): 5 byte
  • Offset (int): 4 byte
  • 01.235.164,106 mila
  • Dimensioni (breve): 2 byte
  • Bandiere (byte): 1 byte
  • Source (byte): 1 byte
  • LastWriteTime (lungo): 8 byte

Quindi: 5 + 4 + 2 + 1 + 1 + 8 = 21 byte.
Questo succede perché Marshal.SizeOf restituisce 24, perché? E sembra che la i byte in eccesso sono posizionati dopo i byte della stringa, infatti per esempio la seguente struttura:

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

viene convertito seguente tampone:

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

Il quinto , sesto e settimo sono i byte in eccesso. Come posso risolvere questo problema?

+0

La stringa ha una lunghezza strana, quindi gli altri campi sono stati riallineati. L'uso di Explicit Layout può risolvere il problema. "Sequenziale" non significa "contiguo". – harold

+0

La stringa ha sempre la stessa lunghezza? – SynerCoder

+0

@SynerCoder yes, un massimo di 5 byte. – Nick

risposta

7

Stai riscontrando un problema di allineamento dei byte. Nel tentativo di mantenere i campi sui confini delle parole per la velocità di accesso, il compilatore riempie il tuo string con 3 byte in più. Per risolvere questo problema, utilizzare il campo Pack di StructLayoutAttribute.

[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

Esatto. Funziona perfettamente. Grazie. – Nick

0

È possibile utilizzare uno fixed size buffer anziché una stringa.

[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

Beh, questo è ak, la domanda ha già risposto ... – SynerCoder

+2

Questo dà una dimensione di 32, non 21. Anche se si sostituisce 'char' con' byte', si ottiene ancora 24 dalla chiamata 'Marshal.SizeOf()'. –

+0

@MattDavis in mia difesa Non ho mai lavorato molto con le strutture: p – SynerCoder

Problemi correlati