【发布时间】:2013-06-10 01:59:13
【问题描述】:
在unsafe 块中,我试图获取指向byte 数组的指针。但是根据数组的声明大小,我会得到不同的结果:
unsafe {
byte[] bytes;
bytes = new byte[1];
fixed(void* pBytes = bytes)
{
((int)pBytes).Dump(); //prints e.g. 41797644
}
bytes = new byte[0];
fixed(void* pBytes = bytes)
{
((int)pBytes).Dump(); //prints 0 ?!
}
}
如果我打开即时窗口并输入&bytes,我会得到字节数组的实际地址,包括空数组的情况。
为什么fixed 非托管指针的工作方式不同?
更新:
这是相同的代码以及我从即时窗口中得到的内容:
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.
}
}
数组对象的地址(&bytes)和数组指针之间的 8 字节差异由对象的标头解释。
内存中的数组表示为:
type id size elem 0 elem1 ...
----|--------|--------|--------|--------|...
^ 4Bytes 4Bytes ^
| `--< pBytes
`--< &bytes
不安全的指针实际上指向实际数据的开始(即将编组到非托管上下文的数据)
有没有办法在代码中获取空数组的实际地址?
FWIW,我实际上需要它才能访问数组的标头,以便即时修改数组的运行时类型。
【问题讨论】:
-
即时修改数组的运行时类型 - 为什么不创建一个新数组呢?似乎您的方法可能会破坏整个过程的类型安全。
-
我知道我会为此大喊大叫 :) 好的,用例是在 byte[] 和 sbyte[] 之间即时转换。 (这几乎适用于强制转换,但像 Array.Copy() 这样的方法不喜欢混合 sbyte 和 byte 数组
-
这个问题看起来像XY problem。
-
@Rakkun 可能,但我认为这仍然是一个有趣的问题,我希望从中获得一些见解。
-
Henk 是正确的:在任何情况下,您都不应该像这样搞乱对象的内部状态。为了伪造 Array.Copy 而不是搞乱可能导致整个运行时崩溃的内部状态,为什么不编写自己的允许复制的 Array.Copy
byte到sbyte?