C# 为什么结构的sizeof是不安全的
报告明确指出 对于所有其他类型,包括结构,sizeof运算符只能 不能在不安全的代码块中使用 更准确的说法是:C# 为什么结构的sizeof是不安全的,c#,struct,sizeof,C#,Struct,Sizeof,报告明确指出 对于所有其他类型,包括结构,sizeof运算符只能 不能在不安全的代码块中使用 更准确的说法是: 未指定将成员打包到结构中的顺序 出于对齐目的,开头可能有未命名的填充 在一个结构中,在一个结构中,在结构的末尾 用作填充的位的内容是不确定的 当应用于具有结构类型的操作数时,结果是该类型变量中的总字节数,包括任何填充 但是,CLR将如何处理以下结构: [StructLayout(LayoutKind.Explicit, Size = 1, Pack = 1)] public struc
[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(myemptystuct)
计算这些结构的大小时,编译器抛出以下错误:
“*”没有预定义的大小,因此sizeof只能
在不安全的环境中使用
我想知道为什么在这种情况下使用
sizeof
被认为是不安全的。这个问题不是为了寻求解决办法,也不是为了寻找计算结构大小的正确方法,而是为了关注原因。问题中有很多错误的假设,我将逐一解决:
在MyStruct中,我们明确地执行布局
你没有。[StructLayout]属性只有在封送结构值时才真正有效。StructureToPtr(),也由pinvoke封送员使用。只有这样,才能保证封送的值具有请求的布局。CLR保留其认为合适的布局结构的权利。它将对齐结构成员,以便使用结构的代码尽可能快,必要时插入空字节。如果这样的填充字节留有足够的空间,它甚至会交换成员以获得更小的布局。除了使用调试器查看访问结构成员的机器代码之外,这是完全不可发现的。某些[StructLayout]属性确实会影响布局LayoutKind。Explicit实际上支持声明联合。映射算法的确切细节没有文档记录,可能会发生更改,并且在很大程度上取决于目标机器的体系结构
结果是该类型变量的总字节数,包括任何填充
事实并非如此,实际结构可以小于声明的结构。可以通过将成员交换到填充中来实现
这个结构应该在内存中有一个1字节的大小
这种情况很少发生。本地变量也在内存中对齐,在32位处理器上对齐4字节,在64位处理器上对齐8字节。除非结构存储在数组中,否则它在堆栈上或堆上的对象内部实际上需要4或8个字节。此对齐非常重要,原因与成员对齐非常重要相同
MyEmptyStruct为空,我们可以假设内存中的大小为0字节
即使结构为空,变量始终至少有1个字节。这避免了诸如具有占用零字节的非空数组之类的歧义。还有其他语言的规则,比如C++ + < /P>
为什么在这种情况下使用sizeof被认为是不安全的
需要明确的是,在原语值类型上使用sizeof并不需要不安全,因为.NET2。但对于结构,sizeof()可能直接用于寻址内存,例如将其添加到IntPtr中。使用sizeof()可能是错误的选择,应该改为Marshal.sizeof()。我猜在结构上使用sizeof()的实用性很低,因为一个结构应该总是很小的,并且以错误的方式攻击intptr的几率很高,以至于他们让它变得不安全
我想知道为什么在这种情况下使用sizeof被认为是不安全的
马修·沃森的评论一针见血。你打算用安全代码处理这些信息吗?它对任何东西都没有用处(*)。它不会告诉您需要为封送分配多少非托管字节;这是Marshal.SizeOf
。它只对指针运算有用,那么为什么它应该在安全子集中呢
(*)说句公道话,safe
sizeof
可以接受包含托管类型的结构,这里有一些奇怪的角落用法。例如,假设您有一个通用集合类,该类将分配一组数组,并希望确保这些数组不会移动到大型对象堆中;如果您可以采用包含托管对象的结构的大小,那么您可以非常轻松地编写此代码,并且不需要任何指针算法。但事实仍然是,sizeof
是专门为指针算法设计的,而不是为了让您可以对数组的垃圾收集启发式进行结束运行。Skeet在这里的回答是:很好。我还没有看到它不安全的原因。我猜编译器需要它来强化这样一个概念,即sizeof(struct)
将根据x86/x64设置等而变化,因此这样做有点不安全。但是仅仅询问结构的大小并不是不安全的,正如获取和使用指向内存块的指针是不安全的一样。这不是上面链接的问题的重复-另一个问题问你为什么不能得到a的大小