2012-11-05 11 views
5

I habe die folgende StrukturMarshal.SizeOf Struktur liefert übermäßige Anzahl

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

} 

Muss der Struktur auf ein Array von Bytes konvertieren (als Paket mit Sockel senden), so verwende ich die GetBytes Methode, aber es gibt ein Array von Bytes 24 anstelle eines Arrays von 21 Bytes:

  • Dateiname (string): 5 Byte
  • Offset (int): 4 Byte
  • Größe (kurz): 2 Byte
  • Flags (Byte): 1 Byte
  • Quelle (Byte): 1 Byte
  • Lastwritetime (lang): 8 Byte

So: 5 + 4 + 2 + 1 + 1 + 8 = 21 Bytes.
Das passiert, weil Marshal.SizeOf 24 zurückgibt, warum? Und es scheint, dass die die Bytes im Überschuss nach dem Bytes der Zeichenfolge gespeichert werden und die folgenden Struktur in der Tat zum Beispiel:

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

Die fünfte:

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

den folgenden Puffer umgewandelt wird, , sechste und siebte sind die Bytes im Übermaß. Wie kann ich dieses Problem lösen?

+0

Die Zeichenfolge hat eine seltsame Länge, so dass die anderen Felder neu ausgerichtet wurden. Mit Explicit Layout kann das behoben werden. "Sequenziell" bedeutet nicht "zusammenhängend". – harold

+0

Hat die Saite immer die gleiche Länge? – SynerCoder

+0

@SynerCoder ja, maximal 5 Bytes. – Nick

Antwort

7

Sie stoßen auf ein Byte-Alignment-Problem. In einem Versuch, Felder auf Wortgrenzen für die Geschwindigkeit des Zugriffs zu halten, füllt der Compiler Ihre string mit 3 zusätzlichen Bytes. Um dies zu beheben, verwenden Sie das Feld Pack des 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

Das stimmt. Es funktioniert perfekt. Vielen Dank. – Nick

0

Sie könnten eine fixed size buffer anstelle einer Zeichenfolge verwenden.

[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

Nun, das ist akward, Frage bereits beantwortet ... – SynerCoder

+2

Das ergibt eine Größe von 32, nicht 21. Auch wenn Sie 'char' durch' byte' ersetzen, erhalten Sie immer noch 24 aus dem 'Marshal.SizeOf()' Aufruf. –

+0

@MattDavis in meiner Verteidigung Ich habe nie viel mit Structs gearbeitet: p – SynerCoder

Verwandte Themen