我使用结构来表示纯数据。其中一个字段是固定大小的缓冲区,如下所示。
[StructLayout(LayoutKind.Sequential, Pack=2)]
unsafe struct ImageDosHeader
{
...
private fixed ushort _e_res[4];
...
[Description("Reserved")]
[DisplayName("e_res[0]")]
public ushort e_res_0 { get { ... } set { ... } }
...
}
在 get/set 函数中,我尝试执行以下操作,但收到“编译器错误 CS1666:您不能使用未固定表达式中包含的固定大小缓冲区。尝试使用固定语句。”
return this._e_res[0];
然而,以下工作:
fixed (ImageDosHeader* p = &this)
return p->_e_res[0];
ImageDosHeader local = this;
return local._e_res[0];
我可以轻松使用这些解决方法,但是,我想知道为什么直接访问固定大小的缓冲区是非法的。或者这是我应该报告的错误?
我正在使用.NET 2.0。
这是因为底层的 IL 指令。
该程序执行以下指令序列来获取您想要的元素:
将地址加载到堆栈上。
将偏移量加载到堆栈上。
添加它们。
读取该内存地址处的值。
如果该对象位于堆中,然后在步骤 4 之前由于垃圾回收而移动,则从步骤 1 加载的地址将不再有效。为了防止这种情况,您需要首先将对象固定到内存中。
(事实上,您正在通过this
指针意味着您不知道该结构是在堆上还是在堆栈上,因此您必须固定它以防万一它在堆上。)
第二个例子之所以有效,是因为它copies的结构stack,因此副本永远不会移动,因此地址将始终有效。
为什么其他类型的字段不会出现同样的问题?因为它们的偏移已知为编译时,而数组索引已知为run-time,因此 JIT 可以生成始终正确访问字段的代码。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)