固定大小缓冲区不能直接从“this”使用目的
我使用结构来表示纯数据。其中一个字段是固定大小的缓冲区,如下所示。
[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。
I am used a structure to represent pure data. One of the fields is a fixed-size buffer, as shown below.
[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 { ... } }
...
}
Within the get/set functions I tried to do the following but I get "Compiler Error CS1666: You cannot use fixed size buffers contained in unfixed expressions. Try using the fixed statement."
return this._e_res[0];
However, the following work:
fixed (ImageDosHeader* p = &this)
return p->_e_res[0];
ImageDosHeader local = this;
return local._e_res[0];
I can easily use the workarounds, however, I am wondering why directly accessing the fixed-size buffer from this is illegal. Or is this a bug that I should report?
I am using .NET 2.0.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
这是因为底层的 IL 指令。
程序执行以下指令序列来获取所需的元素:
将地址加载到堆栈上。
将偏移量加载到堆栈上。
添加它们。
读取该内存地址处的值。
如果该对象位于堆中,然后在步骤 4 之前由于垃圾回收而移动,则从步骤 1 加载的地址将不再有效。为了防止这种情况,您需要首先将对象固定到内存中。
(事实上,您通过
this
指针访问该结构意味着您不知道该结构是在堆上还是在堆栈上,因此您必须固定它,以防万一它在堆。)第二个示例之所以有效,是因为它将结构复制到堆栈,因此副本永远不会移动,因此地址始终有效。
为什么其他类型的字段不会出现同样的问题?因为它们的偏移量在编译时已知,而数组索引在运行时已知,因此 JIT 可以生成始终正确访问字段的代码。
It's because of the underlying IL instructions.
The program does this sequence of instructions to get the element you want:
Load the address onto the stack.
Load the offset onto the stack.
Add them.
Read the value at that memory address.
If the object is in the heap and then moves because of garbage collection before step 4, then the address loaded from step 1 will no longer be valid. To protect against this, you need to pin the object into memory first.
(The fact that you're accessing the structure through the
this
pointer means that you have no idea if the structure is on the heap or on the stack, so you have to pin it just in case it's on the heap.)The second example works because it copies the structure to the stack, and so the copy can never move around, so the address will always be valid.
Why doesn't the same issue happen with other kinds of fields? Because their offset is known at compile-time, whereas the array index is known at run-time, so the JIT can generate code that will always access the fields correctly.
你看待
fixed
关键字的角度改变了它的语义,这是相当令人困惑的。fixed
语句的最初目的是将一块可直接传送的内存固定到位,在 C# 2.0 中,它与字段声明一起使用来表示“该数组恰好是 N” /em> elements long',因此具有固定大小,在内存中不固定。我会去掉字段声明中的
fixed
关键字,只使用:这样,该结构仍然是可 blittable 的,并且使用起来并不麻烦。
The perspective from which you look at the
fixed
keyword changes its semantics, which is rather confusing. Thefixed
's statement original purpose has been to pin a piece of blittable memory in place, in C# 2.0 it is used along with a field declaration to denote that 'the array is exactly N elements long', thus, of fixed size, not fixed in memory.I'd get rid of the
fixed
keyword in field declaration and just use:This way, the struct is still blittable and not a pain in the butt to work with.