6

私は次の構造を持っています

[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 バイト
  • オフセット (整数): 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)

5 番目、6 番目、7 番目は超過バイトです。どうすればこの問題を解決できますか?

4

2 に答える 2

10

バイト アラインメントの問題が発生しています。アクセス速度のためにフィールドをワード境界に保持しようとして、コンパイラはstring3 バイト余分にパディングします。これを修正するには、 のPackフィールドを使用します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;
}
于 2012-11-05T14:32:50.300 に答える
0

文字列の代わりに固定サイズのバッファを使用できます。

[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
    }
}
于 2012-11-05T14:35:05.313 に答える