为什么sizeof结构是不安全的

MSDN明确指出

对于所有其他类型,包括结构体,sizeof运算符只能用于不安全的代码块。

C#语言规范更加精确:

  • 未指定将成员打包到结构中的顺序。
  • 出于对齐的目的,在结构的开始处,结构内以及结构的末端可能存在未命名的填充。
  • 用作填充的位的内容是不确定的。
  • 当应用于具有结构类型的操作数时,结果是该类型变量中的总字节数,包括任何填充。
  • 但是,CLR如何处理以下结构:

    [StructLayout(LayoutKind.Explicit, Size = 1, Pack = 1)]
    public struct MyStruct
    {
        [FieldOffset(0)] public byte aByte;
    }
    
    public struct MyEmptyStruct { }
    

    MyStruct我们显式地强制布局,大小以及如何通过StructLayout属性打包它。 该结构应该在内存中具有1个字节的大小。

    另一方面, MyEmptyStruct是空的,我们可以假设内存中的大小是0字节 - 即使这样的结构很可能不会被使用,它仍然是一个有趣的案例。

    当试图使用sizeof(MyStruct)sizeof(MyEmptyStruct)来计算这些结构的大小时,编译器会引发以下错误:

    '*'没有预定义的大小,因此sizeof只能用于不安全的上下文中

    我想知道为什么在这种情况下使用sizeof被认为是unsafe 。 这个问题不是要求解决方法,也不是要求计算结构大小的正确方法,而是要关注原因。


    我想知道为什么在这种情况下使用sizeof被认为是不安全的。

    马修沃森的评论击中了头部。 你将如何处理这些安全代码中的信息? 这对任何事情都没有用(*)。 它不会告诉你需要分配给编组的多少个非托管字节; 那是Marshal.SizeOf 。 它只对指针算术有用,为什么它应该在安全子集中​​?


    (*)可以公平地说,有一些奇怪的角落案例用于安全sizeof ,可以采取包含托管类型的结构。 假设你有一个通用的集合类,它将分配一堆数组,并希望确保这些数组不会移动到大对象堆中; 如果你可以采用包含托管对象的结构的大小,那么你可以很容易地编写这些代码,并且它不需要任何指针算术。 但事实仍然是sizeof是专门为指针算术设计的,而不是你可以围绕数组的垃圾收集启发式做一个末端运行。


    在这个问题上有很多错误的假设,我会逐一解决它们:

    在MyStruct中,我们明确地强制布局

    你没有。 当结构值被编组时,[StructLayout]属性才真正有效。 Marshal.StructureToPtr(),也被pinvoke编组使用。 只有这样才能保证编组值符合要求的布局。 CLR保留根据其认为适当的布局结构的权利。 它将对齐结构成员,以便使用该结构的代码尽可能快,必要时插入空字节。 如果这种填充字节留下足够的空间,那么它甚至会交换成员以获得更小的布局。 除了使用调试器来查看访问结构成员的机器代码以外,这完全是不可发现的。 一些[StructLayout]属性确实会影响布局,LayoutKind.Explicit实际上支持声明联合。 映射算法的确切细节未经证实,可能会有所变化,并且主要取决于目标机器架构。

    结果是该类型变量的总字节数,包括任何填充。

    不是,实际的结构可能比声明的结构小。 可以通过交换成员到填充。

    该结构应该在内存中具有1个字节的大小。

    情况非常少见。 局部变量也在内存中对齐,在32位处理器上为4个字节,在64位处理器中为8个字节。 除非结构体存储在一个数组中,否则它实际上需要4或8个字节的堆栈或堆内的对象。 这种对齐非常重要,因为成员对齐很重要。

    MyEmptyStruct是空的,我们可以假设内存中的大小是0字节

    即使结构为空,变量也将始终有至少1个字节。 这避免了含有零字节的非空数组之类的含糊之处。 也是其他语言的规则,如C ++。

    为什么在这种情况下使用sizeof被认为是不安全的

    要明确的是,在基本值类型上使用sizeof并不需要从.NET 2开始的不安全。但是对于结构,sizeof()可能会直接用于直接寻址内存,并将其添加到IntPtr中。 有相当大的风险,使用sizeof()是错误的选择,应该是Marshal.SizeOf()代替。 我猜测在结构体上使用sizeof()的实用性非常低,因为一个结构体应该总是很小,并且以错误的方式攻击IntPtrs的几率太高,以致于它们不安全。

    链接地址: http://www.djcxy.com/p/72139.html

    上一篇: Why sizeof of a struct is unsafe

    下一篇: sizeof() structures not known. Why?