我有一个包含字段的有序结构..
[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;
}
为什么会出现这种行为差异?
--- 已编辑 -----
只是想再次声明任何其他排列均无效。
unsafe void foo() {
RunBlock_t r = new RunBlock_t();
fixed (byte* ptr = r.raw) for (int i = 0; i < 512; i++) ptr[i] = 0;
}
生成您不能使用固定语句获取已固定表达式的地址并且不编译。
RunBlock_t r;
unsafe void foo() {
r = new RunBlock_t();
for (int i=0; i<512; i++) r.raw[i]=0;
}
生成 您不能使用包含在不固定表达式中的固定大小缓冲区。尝试使用 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();
fixed (byte* ptr = r.raw) for (int i = 0; i < 510; i++) ptr[i] = 0;
}
加注:
You cannot use the fixed statement to take the address of an already fixed expression
如果我们删除 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
< strong>以防万一它是对象上的字段;如果引用结果解析为堆栈,那么它不需要做任何事情 - 请注意,此处关于“对象上的字段”的所有内容同样适用于“数组中的值”,即如果我们谈论的是
someArray[8]
(因为您可以操纵原位阵列)
关于c# - 'fixed' 的要求在 C# 中似乎不一致,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/13095238/