C #: unsafe pointer to empty array is null?

In the unsafe block, I'm trying to get a pointer to a byte array. But I get different results depending on the declared size of the array:

 unsafe { byte[] bytes; bytes = new byte[1]; fixed(void* pBytes = bytes) { ((int)pBytes).Dump(); //prints eg 41797644 } bytes = new byte[0]; fixed(void* pBytes = bytes) { ((int)pBytes).Dump(); //prints 0 ?! } } 

If I open the nearest window and type &bytes , I get the actual addresses of the byte arrays, including the case with an empty array.

Why does the unmanaged fixed pointer work the same way?

UPDATE:

Here is the same code and what I get from the direct window:

 unsafe { byte[] bytes; bytes = new byte[1]; fixed(void* pBytes = bytes) { // bytes => // {byte[1]} // [0]: 0 // // &bytes // 0x0601c34c //the address of the variable // bytes: 0x027dc804 //the address of the array // // pBytes // 0x027dc80c // notice pBytes == (&bytes + 8) // *pBytes: 0 } bytes = new byte[0]; fixed(void* pBytes = bytes) { // bytes => // {byte[0]} // // &bytes // 0x0601c34c //same address of the variable, ofc // bytes: 0x02aa7ad4 //different address of (new) array // // pBytes // 0x00000000 // BOINK // *pBytes: Cannot dereference 'pBytes'. // The pointer is not valid. } } 

The difference of 8 bytes between the address of the array object (& bytes) and the array pointer is explained by the object header.

Representation of an array in memory:

  type id size elem 0 elem1 ... ----|--------|--------|--------|--------|... ^ 4Bytes 4Bytes ^ | `--< pBytes `--< &bytes 

An unsafe pointer actually points to the beginning, well, of the actual data (i.e. what would be associated with an unmanaged context)

Is there a way to get the actual address of an empty array in code?

FWIW, I really need this to be able to get to the header of the array in order to modify the type of the runtime of the array on the fly.

+4
source share
2 answers

Why does a fixed unmanaged pointer work the same way?

This is a strange question. Why do you believe that?

Contract: when you commit an array with n elements, where n> 0, you get a pointer to a buffer from which you can read and write n elements.

Now that n is zero, null is a pointer to a buffer from which you can read and write zero elements, so as it turns out, this contract is actually executed for the case when n is zero. C # language is not required for this. The specification states

The behavior of a fixed operator is determined by the implementation if the array expression is null or the array has null elements.

Thus, the implementation will be completely within its rights, for example, throw an exception in your program. The value of your program is not really defined at all by the C # language specification.

You are trying to use fixed off-label to do something incredibly dangerous and wrong. Do not do this. You should use fixed for an array for only one thing: get a pointer to a buffer of n elements that you can read and write.

Is there a way to get the actual address of an empty array in code?

Yes. Lock manually with GCHandle .

Binding a managed entity to obtain its address is almost always dangerous and incorrect.

I need this to be able to get to the header of the array in order to modify the type of runtime of the array on the fly.

It is always dangerous and wrong. Do not do this under any circumstances.

+12
source

To get the address, do a GCHandle .

See GCHandle for the address (pointer) of a .net object

 GCHandle handle; IntPtr ptr; byte[] bytes; bytes = new byte[1]; handle = GCHandle.Alloc(bytes, GCHandleType.Pinned); ptr = handle.AddrOfPinnedObject(); ptr.ToInt32().Dump(); // Prints 239580124 handle.Free(); unsafe { fixed(void* pBytes = bytes) { ((int)pBytes).Dump(); //prints 239580124 } } bytes = new byte[0]; handle = GCHandle.Alloc(bytes, GCHandleType.Pinned); ptr = handle.AddrOfPinnedObject(); ptr.ToInt32().Dump(); // Prints 239609660 handle.Free(); unsafe { fixed(void* pBytes = bytes) { ((int)pBytes).Dump(); //prints 0 } } 

See Eric Lippert's answer on why he works like this.

+1
source

Source: https://habr.com/ru/post/1486050/


All Articles