在C#中,sizeof用来计算非托管类型(值类型)的大小,不能用来计算托管类型(引用类型)的大小,单位是字节。
当对引用类型进行sizeof的时候,编译后会报错,如代码:
Console.WriteLine(sizeof(string));
将会报错
一、sizeof
1、除了struct,一般的值类型可以直接使用sizeof()来计算其大小,不涉及上下文安全问题,如:
Console.WriteLine(sizeof(int));//4
具体sizeof计算结果如下:
2、至于struct,如果对其使用sizeof()则涉及上下文安全,如代码
public struct TestStruct { public bool TestA; public int TestInt; public bool TestB; }
//用sizeof必须要挂在unsafe 代码下,而且工程属性要设置为支持上下文不安全模式 unsafe { Console.WriteLine(sizeof(TestStruct)); }
此时,输出的字节大小是12,并不是 1 + 4 + 1 = 6。
为啥是12呢,这就涉及到内存对齐。
内存对齐的规则可以点击这里
TestStruct对应的内存是:0xxx|0000|0xxx
如果TestB和TestInt两行对调一下,如下代码
public struct TestStruct2
{
public bool TestA;
public bool TestB;
public int TestInt;
}
此时TestStruct2所占的字节大小是8,对应的内存应该是:00xx|0000
要想TestStruct和TestStruct2所占的内存大小一样的话,可以对TestStruct使用 字段布局[StructLayout(LayoutKind.Auto)]
[StructLayout(LayoutKind.Auto)]
public struct TestStruct
{
public bool TestA;
public int TestInt;
public bool TestB;
}
至于字段布局,可以看这里
二、Marshal.SizeOf
Marshal.SizeOf返回类的非托管大小
Marshal.SizeOf的文档,参看官网
为了帮助理解,关于封送处理,可以参看这里
我测试代码如下:
using System; using System.Runtime.InteropServices; namespace TestCSharp { [StructLayout(LayoutKind.Sequential)] public class TestClass { } [StructLayout(LayoutKind.Sequential)] public struct TestStruct2 { public byte by; public sbyte sb; public bool b; public char c; public short s; public ushort us; public int i; public uint ui; public long l; public ulong ul; public float f; public double d; public decimal dec; public TestClass tc; } internal class Program { public static void Main(string[] args) { TestStruct2 t = new TestStruct2(); t.tc = new TestClass(); Console.WriteLine(Marshal.SizeOf(t.by));//1 Console.WriteLine(Marshal.SizeOf(t.sb));//1 Console.WriteLine(Marshal.SizeOf(t.b));//4 Console.WriteLine(Marshal.SizeOf(t.c));//1 Console.WriteLine(Marshal.SizeOf(t.s));//2 Console.WriteLine(Marshal.SizeOf(t.us));//2 Console.WriteLine(Marshal.SizeOf(t.i));//4 Console.WriteLine(Marshal.SizeOf(t.ui));//4 Console.WriteLine(Marshal.SizeOf(t.l));//8 Console.WriteLine(Marshal.SizeOf(t.ul));//8 Console.WriteLine(Marshal.SizeOf(t.f));//4 Console.WriteLine(Marshal.SizeOf(t.d));//8 Console.WriteLine(Marshal.SizeOf(t.dec));//16 Console.WriteLine(Marshal.SizeOf(t.tc));//1 Console.WriteLine(Marshal.SizeOf(t));//80,#pragma pack(n) 表示设置为n字节对齐。 C#默认应该也是8字节对齐(没有查证),所以t.dec应该是按照8而不是16对齐,这个需要注意 } } }
这个是测试输出的字节大小
(2020.2.25,把引用对象所占的大小去掉了,这个需要看情况算)
其中类的封送不能用[StructLayout(LayoutKind.Auto)],可以改成[StructLayout(LayoutKind.Sequential)]
Marshal.SizeOf所得大小也是按内存对齐规则来的
另:如果sizeof(TestStruct)没有放在unsafe下,如
Console.WriteLine(sizeof(TestStruct));
会有编译错误:
解决办法是:
unsafe
{
Console.WriteLine(sizeof(TestStruct));//用sizeof必须要挂在unsafe 代码下,而且工程属性要设置为支持上下文不安全模式
}
别忘记工程属性要设置为支持上下文不安全模式,否则会报如下编译错误: