我有一个包含字段的有序结构..
[StructLayout(LayoutKind.Explicit)]
public unsafe struct RunBlock_t {
[System.Runtime.InteropServices.FieldOffset(0)] public fixed byte raw[512];
}
如果我在一个函数中声明这个并且想要使用指针,它可以正常工作..
{
RunBlock_t r = new RunBlock_t();
for (int i=0; i<512; i++) r.raw[i]=0;
}
但如果我在范围之外声明变量,则需要一个固定的实现
RunBlock_t r;
{
r = new RunBlock_t();
fixed (byte* ptr = r.raw) for (int i=0; i<510; i++) ptr[i]=0;
}
为什么会出现这种行为差异?
--- EDITED -----
只想再次声明任何其他排列都不起作用。
unsafe void foo() {
RunBlock_t r = new RunBlock_t();
fixed (byte* ptr = r.raw) for (int i = 0; i < 512; i++) ptr[i] = 0;
}
生成 您不能使用fixed语句获取已修复表达式 的地址,也不能编译。
RunBlock_t r;
unsafe void foo() {
r = new RunBlock_t();
for (int i=0; i<512; i++) r.raw[i]=0;
}
生成 您不能使用未固定表达式中包含的固定大小缓冲区。尝试使用fixed语句。 并且不编译。
答案 0 :(得分:5)
你的问题没有任何意义。您可能会将数组与指针混淆,可能是因为在C和C ++中,数组在大多数情况下都会快速降级为指针,包括[]
下标运算符。
但这是C#。数组和指针是完全独立的动物(虽然你可以强制指向一个数组,但你必须在fixed
语句中这样做,以确保指针保持有效)。你应该比较
{
RunBlock_t r = new RunBlock_t();
for (int i=0; i<512; i++) r.raw[i]=0;
}
到
RunBlock_t r;
{
r = new RunBlock_t();
for (int i=0; i<512; i++) r.raw[i]=0;
}
两者都使用数组。或者
{
RunBlock r = new RunBlock_t();
fixed (byte* ptr = r.raw) for (int i=0; i<512; i++) ptr[i]=0;
}
到
RunBlock_t r;
{
r = new RunBlock_t();
fixed (byte* ptr = r.raw) for (int i=0; i<512; i++) ptr[i]=0;
}
两者都使用指针。
然后您将看到声明变量的范围与需要fixed
完全没有关系。
答案 1 :(得分:4)
不幸的是,你有点混淆了这个问题。如果我从问题完全复制,那么这很好用:
{
RunBlock_t r = new RunBlock_t();
for (int i = 0; i < 512; i++) r.raw[i] = 0;
}
和此:
RunBlock_t r;
{
r = new RunBlock_t();
fixed (byte* ptr = r.raw) for (int i = 0; i < 510; i++) ptr[i] = 0;
}
提出:
您不能使用fixed语句获取已修复表达式的地址
如果我们移除fixed
,它就会有效。
你应该展示的是功能签名,即
RunBlock_t r;
unsafe void Bar()
{
{
r = new RunBlock_t();
fixed (byte* ptr = r.raw) for (int i = 0; i < 510; i++) ptr[i] = 0;
}
}
现在意义变得更加清晰了。您可以看到,当您使用fixed
访问值中的固定缓冲区时,您实际上并未修复缓冲区,也无法修复值 ;您实际修复的内容是包含对象,即具有r
字段的对象。这是为了防止GC在堆栈上移动它,如果我们当时将它作为指针访问它将是不好的。在上面的示例中,我们的表达式实际上是fixed (byte* ptr = this.r.raw)
,而固定的东西是:this
。
如果我们仅将结构体作为本地结构,则会有所不同。当地人在堆栈;它们(如前面的消息所暗示的那样)已经修复; GC从不重新定位堆栈。
所以:
fixed
- 您只是直接将其作为指针访问(通过ldloca
)fixed
,在操作期间将对象固定到位ref RunBlock_t
参数),则必须使用fixed
以防万一它是物体上的一个场;如果引用结果是解析到堆栈,则它不需要做任何事情someArray[8]
(因为您可以原位操作数组的内容)< / LI>