sizeof(T)和Unsafe.SizeOf< T>()有什么区别? [英] What's the difference between sizeof(T) and Unsafe.SizeOf<T>()?

查看:221
本文介绍了sizeof(T)和Unsafe.SizeOf< T>()有什么区别?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

首先,在实际问题之前有一个小的免责声明:

First of all, a small disclaimer before the actual question:

我知道关于sizeof运算符和Marshal.SizeOf<T>方法之间的区别有很多封闭/重复的问题,而且我确实了解两者之间的区别.在这里,我谈论的是新Unsafe类中的SizeOf<T>方法

I know there are a lot of closed/duplicate questions regarding the difference between the sizeof operator and the Marshal.SizeOf<T> method, and I do understand the difference between the two. Here I'm talking about the SizeOf<T> method in the new Unsafe class

因此,我不确定我是否了解这两个操作之间的实际区别,尤其是在struct/class上使用该方法时是否存在特定区别.

So, I'm not sure I understand the actual difference between these two operations, and whether there's a specific difference when using the method on a struct/class in particular.

sizeof运算符采用类型名称,并返回分配时应该占用的托管字节数(即,Int32将返回4).

The sizeof operator takes a Type name and returns the number of managed bytes it is supposed to take up when allocated (ie. an Int32 will return 4, for example).

Unsafe.SizeOf<T>方法是在IL中实现的,与Unsafe类中的所有其他方法一样,并在代码中查看其作用:

The Unsafe.SizeOf<T> method on the other hand, is implemented in IL like all the other methods in the Unsafe class, and looking at the code here's what it does:

.method public hidebysig static int32 SizeOf<T>() cil managed aggressiveinlining
{
    .custom instance void System.Runtime.Versioning.NonVersionableAttribute::.ctor() = ( 01 00 00 00 )
    .maxstack 1
    sizeof !!T
    ret
}

现在,如果我没记错的话,代码只是调用sizeof !!T,而该代码与sizeof(T)相同(调用类型名称为Tsizeof运算符),所以两者不会它们完全相等吗?

Now, if I'm not wrong, the code is just calling sizeof !!T wich is the same as sizeof(T) (calling the sizeof operator with the type name T), so wouldn't the two of them be exactly equivalent?

此外,我看到该方法还在第一行中分配了一个无用的对象(NonVersionableAttribute),所以这不会导致少量的内存也进行堆分配吗?

Also, I see the method is also allocating a useless object (the NonVersionableAttribute) in the first line, so wouldn't that cause a small amount of memory to be heap-allocated as well?

我的问题是:

可以肯定地说这两种方法是完全等效的,因此最好使用经典的sizeof运算符,因为这样也可以避免在SizeOf<T>方法中分配该属性?此时,是否为了方便起见将此SizeOf<T>方法添加到了Unsafe类中?

Is it safe to say that the two methods are perfectly equivalent and that therefore it is just better to use the classic sizeof operator, as that also avoid the allocation of that attribute in the SizeOf<T> method? Was this SizeOf<T> method added to the Unsafe class just for convenience at this point?

推荐答案

虽然此方法实际上仅使用sizeof IL指令-与常规sizeof运算符有所不同,因为该运算符不能应用于任意类型:

While this method indeed just uses sizeof IL instruction - there is a difference with regular sizeof operator, because this operator cannot be applied to arbitrary types:

用于获取非托管类型的大小(以字节为单位).不受管理 类型包括表中列出的内置类型,这些类型包括: 以及以下内容:

Used to obtain the size in bytes for an unmanaged type. Unmanaged types include the built-in types that are listed in the table that follows, and also the following:

枚举类型

指针类型

不包含任何内容的用户定义结构 引用类型的字段或属性

User-defined structs that do not contain any fields or properties that are reference types

如果您尝试编写Unsafe.SizeOf的类似物-将不起作用:

If you try to write analog of Unsafe.SizeOf - it will not work:

public static int SizeOf<T>()
{
    // nope, will not compile
    return sizeof(T);
}

因此Unsafe.SizeOf取消了sizeof运算符的限制,并允许您将IL sizeof指令用于任意类型(包括将返回引用大小的引用类型).

So Unsafe.SizeOf lifts restrictions of sizeof operator and allow you to use IL sizeof instruction with arbitrary types (including reference types for which it will return size of reference).

关于在IL中看到的属性构造,这并不意味着将为每个调用实例化属性-仅仅是将属性与各种成员相关联的IL语法(在这种情况下为方法).

As for attribute construct you see in IL - that does not mean attribute will be instantiated for each call - that's just IL syntax for associating attributes with various members (method in this case).

示例:

public struct Test {
    public int Int1;
}

static void Main() {
    // works
    var s1 = Unsafe.SizeOf<Test>();
    // doesn't work, need to mark method with "unsafe"
    var s2 = sizeof(Test);            
}

另一个例子:

public struct Test {
    public int Int1;
    public string String1;
}


static unsafe void Main() {
    // works, return 16 in 64bit process - 4 for int, 4 for padding, because
    // alignment of the type is the size of its largest element, which is 8
    // and 8 for string
    var s1 = Unsafe.SizeOf<Test>();
    // doesn't work even with unsafe, 
    // cannot take size of variable of managed type "Test"
    // because Test contains field of reference type (string)
    var s2 = sizeof(Test);                        
} 

这篇关于sizeof(T)和Unsafe.SizeOf&lt; T&gt;()有什么区别?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆