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对齐,这个需要注意
        }
    }
}

 这个是测试输出的字节大小

 其中类的封送不能用[StructLayout(LayoutKind.Auto)],可以改成[StructLayout(LayoutKind.Sequential)]

Marshal.SizeOf所得大小也是按内存对齐规则来的

 

另:如果sizeof(TestStruct)没有放在unsafe下,如

Console.WriteLine(sizeof(TestStruct));

会有编译错误:

解决办法是:

unsafe
{
  Console.WriteLine(sizeof(TestStruct));//sizeof必须要挂在unsafe 代码下,而且工程属性要设置为支持上下文不安全模式
}

 别忘记工程属性要设置为支持上下文不安全模式,否则会报如下编译错误:

 

猜你喜欢

转载自www.cnblogs.com/woniu89/p/12355172.html
今日推荐