fixed 语句(C# 参考)

fixed 语句可防止垃圾回收器重新定位可移动变量,并声明指向该变量的指针:

unsafe
{
    byte[] bytes = { 1, 2, 3 };
    fixed (byte* pointerToFirst = bytes)
    {
        Console.WriteLine($"The address of the first array element: {(long)pointerToFirst:X}.");
        Console.WriteLine($"The value of the first array element: {*pointerToFirst}.");
    }
}
// Output is similar to:
// The address of the first array element: 2173F80B5C8.
// The value of the first array element: 1.

固定变量的地址在语句的持续时间内不会更改。 只能在相应的 fixed 语句中使用声明的指针。 声明的指针是只读的,无法修改。

注意

只能在不安全的上下文中使用 fixed 语句。 必须使用 AllowUnsafeBlocks 编译器选项来编译包含不安全块的代码。

可以按如下所示初始化声明的指针:

  • 使用数组,如本文开头的示例所示。 初始化的指针包含第一个数组元素的地址。

  • 使用变量的地址。 使用 address-of & 运算符,如以下示例所示:

    unsafe
    {
        int[] numbers = { 10, 20, 30 };
        fixed (int* toFirst = &numbers[0], toLast = &numbers[^1])
        {
            Console.WriteLine(toLast - toFirst);  // output: 2
        }
    }
    

    对象字段是可以固定的可移动变量的另一个示例。

    当初始化的指针包含对象字段或数组元素的地址时,fixed 语句保证垃圾回收器在语句主体执行期间不会重新定位或释放包含对象实例。

  • 使用实现名为 GetPinnableReference 的方法的类型的实例。 该方法必须返回非托管类型ref 变量。 .NET 类型 System.Span<T>System.ReadOnlySpan<T> 使用此模式。 可以固定跨度实例,如以下示例所示:

    unsafe
    {
        int[] numbers = { 10, 20, 30, 40, 50 };
        Span<int> interior = numbers.AsSpan()[1..^1];
        fixed (int* p = interior)
        {
            for (int i = 0; i < interior.Length; i++)
            {
                Console.Write(p[i]);  
            }
            // output: 203040
        }
    }
    

    有关详细信息,请参阅 Span<T>.GetPinnableReference() API 参考。

  • 使用字符串,如以下示例所示:

    unsafe
    {
        var message = "Hello!";
        fixed (char* p = message)
        {
            Console.WriteLine(*p);  // output: H
        }
    }
    
  • 使用固定大小的缓冲区

可以在堆栈上分配内存,在这种情况下,内存不受垃圾回收的约束,因此不需要固定。 为此,请使用 stackalloc 表达式

还可以使用 fixed 关键字声明固定大小的缓冲区

C# 语言规范

有关更多信息,请参阅 C# 语言规范的以下部分:

有关基于模式的 fixed 语句的信息,请参阅基于模式的 fixed 语句功能建议说明。

请参阅