C#的sizeof和Marshal.SizeOf


在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 代碼下,而且工程屬性要設置為支持上下文不安全模式
}

 別忘記工程屬性要設置為支持上下文不安全模式,否則會報如下編譯錯誤:

 

 

 

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM