c# - 'fixed' 的要求在 C# 中似乎不一致

标签 c# pointers fixed

我有一个包含字段的有序结构..

[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/

相关文章:

C#:如何在计时期间停止计时器

c# - 让多个进程读取同一个文件的正确方法?

c# - 如何在 Excel 中保留 Excel 功能区加载项的数据

c++ - 函数内部动态分配的内存泄漏

c - Swig 中 C 指针的访问器函数

javascript - 从固定定位的 float 元素计算 "left"和 "top"值

c# - 在客户端将服务器端 OnClientclick 更改为 jQuery

c - C中的程序解释

html - 响应式网站 - ios 修复了页脚问题

html - 固定内容滚动布局