我知道Marshal.SizeOf()
和sizeof()
在本质上有很大不同。但是在IntPtr
的情况下,无论CPU架构如何,它们都会始终返回完全相同的内容,对吗?
首先,有原始类型:
| | x64 | x86 | | Marshal. | Marshal. | |Primitive | SizeOf() sizeof(T) | SizeOf() sizeof(T) | |========= | =========== =========== | =========== =========== | Boolean | 4 <-> 1 | 4 <-> 1 | | Byte | 1 1 | 1 1 | | SByte | 1 1 | 1 1 | | Int16 | 2 2 | 2 2 | | UInt16 | 2 2 | 2 2 | | Int32 | 4 4 | 4 4 | | UInt32 | 4 4 | 4 4 | | Int64 | 8 8 | 8 8 | | UInt64 | 8 8 | 8 8 | | IntPtr | 8 8 <-> 4 4 | | UIntPtr | 8 8 <-> 4 4 | | Char | 1 <-> 2 | 1 <-> 2 | | Double | 8 8 | 8 8 | | Single | 4 4 | 4 4 |ValueType
)实例,其内部管理布局和编组图像之间可能存在显着差异,无论是总大小还是字段布局顺序。后者甚至适用于所谓的格式化类。[1]
实际上很少需要关于实际管理的结构布局的信息,事实上.NET在试图使其不可发现方面付出了很大的努力。您也无法影响结构的内部布局,这正是Marshal
层提供特定声明所需布局的能力的原因,以进行互操作。ValueType 类型进行参数化,该类型定义“记录”或表条目。为了确定可以放入每个托管数组块中的结构体数量,您需要在运行时发现给定结构体的真实大小,以便您可以将 84,800 除以该值。
有关 marshaling 对比 managed-internal 结构布局、填充和大小可能出现的差异的更详细的检查,请参见我对 "How do I check the number of bytes consumed by a structure?" 的扩展回答。
[1.] "一个格式化类是一种引用类型,其布局由StructLayoutAttribute属性指定,可以是LayoutKind.Explicit 或 LayoutKind.Sequential。"
https://msdn.microsoft.com/zh-cn/library/2zhzfk83(v=vs.110).aspx
sizeof
和Marshal.SizeOf
返回值的假设。你会使用marshaller来marshal你的任何实例吗?那就用Marshal.SizeOf
。你的变量从未离开托管世界,或者你正在使用自定义marshalling吗?那就使用sizeof
(或IntPtr.Size
,因为它不需要unsafe
块)。在这两种情况下,你都不需要关心它们是否返回相同的值。这就是实际的答案。sizeof(IntPtr)
返回的值是“该类型变量中的总字节数,包括任何填充”(因为IntPtr
是一个结构体)。然而,它还指出,这个值是“实现定义的”。所以,如果你想要技术上的答案,C#规范只是说“自己算一下”。
话虽如此,IntPtr
的文档明确指出,在 32 位平台上该类型为 32 位,在 64 位平台上为 64 位,并且 ECMA-335 文档说明 IntPtr
是一种特殊的内置类型,对应于 native int
,因此我认为我们可以暂时得出结论,即在任何声称遵循规范的实现中,sizeof(IntPtr)
都是可预测的:在 32 位平台上为 4,在 64 位平台上为 8。 IntPtr.Size
是另一种选择,并且它明确记录了这一点。
Marshal.SizeOf(typeof(IntPtr))
是一个不同的东西。它并没有明确说明它将返回什么,除了“未托管类型的大小”;在底层,它调用了CLR中的一些本地代码,询问TypeHelper
获取大小的基础类型。对于IntPtr
,这将返回C++中的sizeof(void*)
,在大多数C++编译器和平台上,32位平台上为4,64位平台上为8。
从技术上讲,sizeof(IntPtr)
和 Marshal.SizeOf(typeof(IntPtr))
可能是不同的。但这通常不是你需要关心的事情,因为在运行时和JIT(或AOT编译器)的组合中,使sizeof(IntPtr)
等于Marshal.SizeOf(typeof(IntPtr))
是很明智的,否则运行时只会让自己的生活更加困难。另一方面,正如我指出的,通常没有任何理由需要依赖它们相同。
sizeof(<type>)
是错误的,因为不能保证(至少对于其他类型)它将返回与Marshal.SizeOf(typeof(<type>))
相同的值。但正如我所说,如果可以_保证_,至少对于IntPtr
来说,这将始终是正确的,那么在我看来,这只是最佳实践、一致性和约定 - 不一定是“错误”的或者仅仅是因为“愚蠢的运气”而起作用。并不是我主张使用sizeof,只是说一下。 - cogumel0