我正在阅读一些代码,其中一部分是:
public static unsafe byte[] GetBytes(uint value, bool BigEndian)
{
byte[] buff = new byte[4];
fixed (byte* pbyte = buff)*((uint*)pbyte) = value;
if (BigEndian)
buff.EndianConvert();
return buff;
}
我知道它只是将单元位置的4个字节放入一个字节数组,但我不知道如何。
我对它的理解是:
(byte* pbyte = buff)
创建并返回一个字节指针pbyte,它指向buff的地址,
(uint*)pbyte
将pbyte的地址转换为uint指针?,
我不了解其余部分。固定关键字有什么用?为什么不能这样做:
(byte* pbyte = buff) = (byte*)value;
答案 0 :(得分:2)
fixed语句阻止垃圾收集器重定位可移动变量。如果你省略它,你的地址可能会改变,你会收到错误
答案 1 :(得分:1)
您不能只获取数组的地址,因为它由垃圾收集器管理,这意味着它在内存中的位置可以随时更改。固定关键字将数组固定在其范围的持续时间内,允许数组的四个字节由(4字节)uint值填充。
答案 2 :(得分:1)
其他人已经解释了固定的概念,但我认为令你感到困惑的事实是,这一切都在一条线上。
fixed (byte* pbyte = buff)*((uint*)pbyte) = value;
相当于:
fixed (byte* pbyte = buff)
{
*((uint*)pbyte) = value;
}
就像这样:
if(someCondition) DoSomething();
相当于:
if(someCondition)
{
DoSomething();
}
那清除了吗?现在显而易见的是,第一部分是变量和相关块的声明,第二部分是赋值。
答案 3 :(得分:0)
在CLR GC过程中,对于普通的GC堆对象(LOH除外),GC会将仍然存活的对象标记并移动到下一代(此操作也命名为promote)。在提升对象A时,GC会将对象A地址从addr-old修改为addr-new,然后更新引用此对象的所有对象的关系。
例如,对象A由对象B和对象C引用,这意味着对象B具有指向对象A的指针,对象C也具有指向对象A的指针。然后,在促销中阶段,对象A的地址将从addr-old更改为addr-new,然后,GC还将修改对象B和对象C的引用指针值。修改后,对象B和C具有仍然指向的正确指针到了现在。
在执行“byte * pbyte = buff”行之后,pbyte有一个指向对象“buff”的指针,假设pbyte地址是0x12345678(也就是说buff addr是0x12345678)。现在,GC发生了,对象“buff”将被提升为新一代,这意味着对象“buff”将有一个新的内存地址,例如,它是“0x55555555”。但是,“pbyte”是一个本机(非托管)对象,CLR不知道如何维护它的'生命周期,所以,尽管pbyte与buff有关系,但CLR无法将pbyte地址从0x12345678更改为0x55555555。然后,指针“pbyte”仍然指向地址0x12345678,但是这个地址不属于对象“buff”,指针“pbyte”现在是一个坏指针。
“fixed”语句将确保托管对象“buff”不会被提升,也意味着不会从这里移动到那里。