фиксированная инструкция — закрепление переменной для операций указателя

Инструкция fixed предотвращает перемещение перемещаемой переменной сборщика мусора и объявляет указатель на нее. Адрес фиксированной или закрепленной переменной не изменяется во время выполнения инструкции. Объявленный указатель можно использовать только в соответствующей 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 можно использовать только в небезопасном контексте . Код, содержащий небезопасные блоки, должен компилироваться с параметром компилятора 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 переменную неуправляемого типа. Типы System.Span<T> .NET и 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
        }
    }
    

    Дополнительные сведения см. в справочной документации по API Span<T>.GetPinnableReference().

  • Со строкой, как показано в следующем примере:

    unsafe
    {
        var message = "Hello!";
        fixed (char* p = message)
        {
            Console.WriteLine(*p);  // output: H
        }
    }
    
  • С буфером фиксированного размера.

Вы можете выделить память в стеке, где она не подлежит сборке мусора и поэтому не требуется закреплять. Для этого используйте выражение stackalloc.

Можно также использовать fixed ключевое слово для объявления буфера фиксированного размера.

Спецификация языка C#

Дополнительные сведения см. в следующих разделах статьи Спецификация языка C#:

См. также