Cannot directly use fixed size buffer from "this" object

I use a structure to represent clean 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 { ... } } ... } 

Inside the get / set functions, I tried the following, but I got "CS1666 compiler error: you cannot use fixed-size buffers contained in uncommitted expressions. Try using a fixed operator."

 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 workarounds, however I wonder why direct access to a fixed-size boom from this is illegal. Or is this a bug I should report?

I am using .NET 2.0.

+8
c # this fixed
source share
2 answers

This is because of the underlying IL instructions.

The program executes this sequence of instructions to get the desired item:

  • Load the address onto the stack.

  • Load the offset on the stack.

  • Add them.

  • Read the value at this memory address.

If the object is on the heap and then moves due to garbage collection until step 4, then the address downloaded from step 1 will no longer be valid. To protect against this, you need to first bind the object to memory.

(The fact that you are accessing the structure using the this pointer means that you do not know if the structure is on the heap or on the stack, so you need to attach it just in case it is on the heap.)

The second example works because it copies the structure onto the stack, so the copy can never move, so the address will always be valid.

Why does this problem not occur with other kinds of fields? Since their offset is known at compile time, while the index of the array is known at run time, so JIT can generate code that will always refer to fields correctly.

+11
source share

The perspective with which you look at the fixed keyword changes its semantics, which is quite confusing. The original purpose of fixed was to attach a piece of blittable memory in place, in C # 2.0 it is used along with a field declaration to indicate that the "array of exactly N elements is long", thus of a fixed size, and not fixed in memory.

I would get rid of the fixed keyword in the field declaration and just use:

 [MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)] private ushort[] _e_res; 

Thus, the structure is still blittable, and not a pain in the junction for work.

+4
source share

All Articles