Marshal.SizeOf结构返回过多的数字

时间:2012-11-05 14:09:19

标签: c# struct 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(long):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)

第五,第六和第七是超出的字节。 我该如何解决这个问题?

2 个答案:

答案 0 :(得分:9)

您遇到了字节对齐问题。为了保持字边界上的字段以获得访问速度,编译器用{3}额外字节填充string。要解决此问题,请使用Pack的{​​{1}}字段。

StructLayoutAttribute

答案 1 :(得分: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
    }
}