C#中sizeof

一.

int size = sizeof (int); //4个字节


注意点:sizeof 运算符仅适用于值类型,而不适用于引用类型。sizeof 运算符只能在不安全代码块中使用。如下面的代码将无法编译通过:

public struct TestStuct{}
int size = sizeof(new TestStuct());

编译后,提示:

错误 1 “ConsoleApplication3.TestStuct”没有预定义的大小,因此 sizeof 只能在不安全的上下文中使用(请考虑使用 System.Runtime.InteropServices.Marshal.SizeOf)

修改为Marshal.SizeOf方法,改方法返回对象的非托管大小(以字节为单位)。参数可以是引用类型或装箱的值类型。布局必须是连续的或显式的。

int size = Marshal.SizeOf(new TestStuct()); //1个字节


接下来来验证引用类型:

由于不能作为非托管结构进行封送处理;无法计算有意义的大小或偏移量。所有下面的代码在运行的时候,会抛出异常。

public class Student
{
}

int size = Marshal.SizeOf(new Student());

需要给Student类,加上一个StructLayoutAttribute,来控制Student类的数据字段的物理布局。修改代码为:

[StructLayout(LayoutKind.Sequential)]
public class Student
{
}

int size = Marshal.SizeOf(new Student()); //1个字节

LayoutKind 默认值为Auto.

结论:
1:对于托管对象是没有办法直接获取到一个对象所占的内存大小。
2:非托管对象,可以使用Marshal.SizeOf
3:对内置类型,如int,long,byte等使用sizeof

扩展:
有人提出使用二进制序列化,将一个对象序列化成一个MemoryStream,然后返回MemoryStream.Length,经过验证是不可以的。

验证代码如下:

[Serializable]
 public class Student
    {
    }

private static long GetObjectSize(object o)
        {
            using (var stream = new MemoryStream())
            {
                var formatter = new BinaryFormatter();
                formatter.Serialize(stream, o);
                using (var fileStream = new FileStream(@"D:\Student.txt", FileMode.OpenOrCreate, FileAccess.Write))
                {
                    var buffer = stream.ToArray();
                    fileStream.Write(buffer, 0, buffer.Length);
                    fileStream.Flush();
                }

                return stream.Length;
            }
        }

 var student = new Student();
 long size = GetObjectSize(student);  //139个字节

Student.txt保存的文本信息如下所示,通过文本信息,可以得知多出来的100多个字节,估计是就是这一串字符串吧。

              JConsoleApplication3, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null   ConsoleApplication3.Student       

//https://ask.csdn.net/questions/164716

 

二.

有下面一段程序

namespace ConsoleApplication2
{
    class Program
    {
        public struct ss
        {
            private char s;
            private char e;
            private char w;
            private char q;
            private char d;
            private char g;
            // private int a;

        }
        static void Main(string[] args)
        {
            char cc = 'f';
            ss s = new ss();
            Console.WriteLine(System.Runtime.InteropServices.Marshal.SizeOf(cc));
            Console.WriteLine(sizeof(char));
            Console.WriteLine(System.Runtime.InteropServices.Marshal.SizeOf(s));
        }
    }
}

输出结果为

1
2
6

问题一:为什么都是char,System.Runtime.InteropServices.Marshal.SizeOf(cc)输出1,而 Console.WriteLine(sizeof(char));输出2呢?
问题二:对于那个struct,输出为6,但是再加入字段private int a;为什么大小为12了呢?a占4个,为什么签名的6个char变成占了8个啊?不是之前输出是6么?

问题一:对于所有其他类型(包括 struct),sizeof 运算符只能在不安全代码块中使用。虽然可以使用 Marshal.SizeOf 方法,但该方法返回的值和 sizeof 返回的值并不总是相同的。Marshal.SizeOf 在已封送处理类型后返回大小,而 sizeof 返回公共语言运行时分配的大小(包括任何空白)。
c sharp 中用的是unicode编码,所以一个char占用两个字节(比如表示一个汉字,需要两个字节)。而在非托管的语言中,字符编码都是8位(比如美国国家标准协会的编码ansi).。

问题二、要从C语言谈起。C语言里面struct的空间大小有个对齐原则,以占据空间最大的那个类型的大小的倍数对齐,也就是在这里,int a占了4字节,那么最终struct必须占据4的
最小倍数,此处正常算出来是10,但是10不是4的倍数,必须补足到12.C#也是一样的道理。这是一种优化机制或者说一种规定罢了。

//https://zhidao.baidu.com/question/128480617.html

三.

//以下三个结构
public struct myStruct
{
    public long lval;//8
    public int ival;//4
}//8+4 = 12 => 字节对齐 16

public struct myStruct1
{
    public long lval;//8
    public int ival;//4
    public string str;//4
}//8+4+4=16 => 字节对齐 16

public struct myStruct2
{
    public long lval;//8
    public int ival;//4
    public object obj;//4
}//8+4+4=16 => 字节对齐 16

public struct myStruct3
{
    public long lval;//8
    public int ival;//4
    public string str;//4
    public object obj;//4
}//8+4+4+4=20 => 字节对齐 24

class Program
{
    static void Main(string[] args)
    {
        int size;
        size = sizeof(int);//返回4
        Console.WriteLine("int 型变量占用" + size.ToString() + "字节");
        size = sizeof(long);//返回8
        Console.WriteLine("long 型变量占用" + size.ToString() + "字节");

        unsafe
        {
            size = sizeof(myStruct); //据说是存在 字节对齐,所以结果为16 
        }
        Console.WriteLine("myStruct 型变量占用" + size.ToString() + "字节");
        
        //Marshal.SizeOf 获取已封送处理类型后的大小,而sizeof返回CLR分配的大小
        size = System.Runtime.InteropServices.Marshal.SizeOf(new myStruct());//返回16
        Console.WriteLine("Marshal.SizeOf方法获得的myStruct占用" + size + "字节");

        size = System.Runtime.InteropServices.Marshal.SizeOf(new mySturct1()); //返回16
        Console.WriteLine("Marshal.SizeOf方法获得的myStruct1占用" + size + "字节");

        size = System.Runtime.InteropServices.Marshal.SizeOf(new mySturct2()); //返回16
        Console.WriteLine("Marshal.SizeOf方法获得的myStruct2占用" + size + "字节");

        size = System.Runtime.InteropServices.Marshal.SizeOf(new mySturct3()); //返回24
        Console.WriteLine("Marshal.SizeOf方法获得的myStruct3占用" + size + "字节");
        Console.ReadKey();
    }
}

 

你可能感兴趣的:(C#中sizeof)