C# 查找类型对象的大小?

C# 查找类型对象的大小?,c#,C#,我定义这个结构 public enum E1 : byte { A, B, C } public enum E2 : byte { D, E, F } [StructLayout(LayoutKind.Sequential, Pack=4)] public struct SomeStruct { public Int32 _var1; //4 byte public E1 _var2; //1 byte(because

我定义这个结构

public enum E1 : byte
{
    A,
    B,
    C
}

public enum E2 : byte
{
    D,
    E,
    F
}

[StructLayout(LayoutKind.Sequential, Pack=4)]
public struct SomeStruct
{
    public Int32  _var1; //4 byte
    public E1     _var2; //1 byte(because Pack is 4 this will take 4 byte)
    public E2     _var3; //1 byte(because Pack is 4 this will take 4 byte) 
    public UInt64 _var4; //8 byte
}
现在,由于我添加了Pack=4的StructLayout属性,我希望我定义的每个变量都将保持数据字段的对齐为4

所以我希望

 int val = Marshal.SizeOf( typeof( SomeStruct ) );
但是我检查了密码,发现val是16

那么它是怎样的呢?

我的误解在哪里

SizeOf
字节指定大小

现在,如果我们计算一下,我们会发现:

  • Int32
    具有
    32
    位,因此
    4
    字节
  • Int64
    具有
    64
    位,因此
    8
    字节
  • 两个
    enum
    s都编码在一个字节上,因此
    1
    byte
加起来就是
1+1+4+8
,因此
14
字节

但是:大多数系统不喜欢使用字节:它们使用字(16位)或dwords(32位)获取和存储数据。由于最小化数据结构会导致截断数据并重新插入数据的操作,因此它充满了尾随零

如果您在这样的系统上工作,编译器可能希望将数据打包成
16位(或更高位)的块。这些更容易:例如,如果您想访问数组中的一个元素,它不必将两个单词提取到内存中,因为结构是在单词之间拆分的

演示数据如何打包的实验:

using System.Runtime.InteropServices;

namespace Foo {

    public enum E1 : byte
    {
        A,
        B,
        C
    }

    public enum E2 : byte
    {
        D,
        E,
        F
    }


    [StructLayout(LayoutKind.Sequential,Pack=4)]
    public struct SomeStruct
    {
        public int  _var1; //4 byte
        public byte     _var2; //1 byte(because Pack is 4 this will take 4 byte)
        public byte     _var3; //1 byte(because Pack is 4 this will take 4 byte) 
        public ulong _var4; //8 byte

        public SomeStruct (int var1, byte var2, byte var3, ulong var4) {
             this._var1 = var1;
             this._var2 = var2;
             this._var3 = var3;
             this._var4 = var4;
        }

    }

}

Foo.SomeStruct i = new Foo.SomeStruct(1302,5,17,1425);
Marshal.SizeOf( typeof( Foo.SomeStruct ) );
sizeof(Foo.SomeStruct);
int size = sizeof(Foo.SomeStruct);
byte[] result = new byte[size];
IntPtr buffer = Marshal.AllocHGlobal(size);
Marshal.StructureToPtr(i, buffer, false);
Marshal.Copy(buffer, result, 0, size);
结果:

{ 22, 5, 0, 0, 5, 17, 0, 0, 145, 5, 0, 0, 0, 0, 0, 0 }
因此,结构被编码为:

0                32   40   48       64                              128
+----------------+----+----+--------+--------------------------------+
| _var1          | _v2| _v3| ------ | _var4                          |
+----------------+----+----+--------+--------------------------------+
如果使用
int
/
uint
对变量进行编码,则会得到:

{ 22, 5, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 145, 5, 0, 0, 0, 0, 0, 0 }
或:


4+1+1+8=14
with
Pack=4
它是
16
@yansof:从
uint
导出
enum
s。文档似乎对
Pack
值有不同的解释:这意味着每个字段都从偏移量
n*2
开始,其中
n
是基于0的元素计数。例如:使用
Pack=2
,字段1从偏移量0开始,字段2从偏移量2开始,字段3从偏移量4开始,等等。基本上:每个字段都被填充。但是,您的答案表明,所有字段都分组在一起,然后在末尾填充。我误解了什么?@Jeroenvanevel:根据一些实验,似乎——至少是Mono编译器——忽略了packing属性。
0       32        64       96      128              192
+--------+--------+--------+--------+----------------+
| _var1  |  _var2 | _var3  | ------ | _var4          |
+--------+--------+--------+--------+----------------+