sizeof(T) 和 Unsafe.SizeOf<T>() 有什么区别?
What's the difference between sizeof(T) and 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 上使用该方法时是否存在特定差异。
sizeof
运算符采用 类型名称 和 return 的 管理字节数 它是应该在分配时占用(例如,Int32
将 return 4)。
另一方面,Unsafe.SizeOf<T>
方法像 Unsafe
class 中的所有其他方法一样在 IL 中实现,查看代码是它的作用:
.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)
相同(调用类型名称为 [=24 的 sizeof
运算符=]), 那么他们两个不是完全等价的吗?
此外,我看到该方法还在第一行分配了一个无用的对象(NonVersionableAttribute
),所以这不会导致少量内存也被分配到堆中吗?
我的问题是:
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
运算符有所不同,因为此运算符不能应用于任意类型:
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:
Enum types
Pointer types
User-defined structs that do not contain any
fields or properties that are reference types
如果您尝试编写 Unsafe.SizeOf
的模拟 - 它不会工作:
public static int SizeOf<T>()
{
// nope, will not compile
return sizeof(T);
}
因此 Unsafe.SizeOf
解除了 sizeof
运算符的限制并允许您使用具有任意类型的 IL sizeof
指令(包括引用类型,它将 return 大小参考)。
至于您在 IL 中看到的属性构造 - 这并不意味着每次调用都会实例化属性 - 这只是将属性与各种成员相关联的 IL 语法(在本例中为方法)。
示例:
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);
}
首先,在实际问题之前的一个小免责声明:
I know there are a lot of closed/duplicate questions regarding the difference between the
sizeof
operator and theMarshal.SizeOf<T>
method, and I do understand the difference between the two. Here I'm talking about theSizeOf<T>
method in the newUnsafe
class
所以,我不确定我是否理解这两个操作之间的实际差异,以及在特定 struct/class 上使用该方法时是否存在特定差异。
sizeof
运算符采用 类型名称 和 return 的 管理字节数 它是应该在分配时占用(例如,Int32
将 return 4)。
另一方面,Unsafe.SizeOf<T>
方法像 Unsafe
class 中的所有其他方法一样在 IL 中实现,查看代码是它的作用:
.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)
相同(调用类型名称为 [=24 的 sizeof
运算符=]), 那么他们两个不是完全等价的吗?
此外,我看到该方法还在第一行分配了一个无用的对象(NonVersionableAttribute
),所以这不会导致少量内存也被分配到堆中吗?
我的问题是:
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 theSizeOf<T>
method? Was thisSizeOf<T>
method added to theUnsafe
class just for convenience at this point?
虽然此方法确实只使用 sizeof
IL 指令 - 与常规 sizeof
运算符有所不同,因为此运算符不能应用于任意类型:
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:
Enum types
Pointer types
User-defined structs that do not contain any fields or properties that are reference types
如果您尝试编写 Unsafe.SizeOf
的模拟 - 它不会工作:
public static int SizeOf<T>()
{
// nope, will not compile
return sizeof(T);
}
因此 Unsafe.SizeOf
解除了 sizeof
运算符的限制并允许您使用具有任意类型的 IL sizeof
指令(包括引用类型,它将 return 大小参考)。
至于您在 IL 中看到的属性构造 - 这并不意味着每次调用都会实例化属性 - 这只是将属性与各种成员相关联的 IL 语法(在本例中为方法)。
示例:
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);
}