在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 代碼下,而且工程屬性要設置為支持上下文不安全模式
}
別忘記工程屬性要設置為支持上下文不安全模式,否則會報如下編譯錯誤: