instrução fixed – fixar uma variável para operações de ponteiro

A instrução fixed impede que o coletor de lixo realoque uma variável móvel e declara um ponteiro para essa variável. O endereço de uma variável fixa, ou fixada, não é alterado durante a execução da instrução. Você pode usar o ponteiro declarado somente dentro da instrução correspondente fixed. O ponteiro declarado é somente leitura e não pode ser modificado:

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.

Observação

Você pode usar a instrução fixed somente em um contexto não seguro. O código que contém blocos não seguros deve ser compilado com a opção do compilador AllowUnsafeBlocks.

Você pode inicializar o ponteiro declarado da seguinte maneira:

  • Com uma matriz, como mostra o exemplo no início deste artigo. O ponteiro inicializado contém o endereço do primeiro elemento de matriz.

  • Com um endereço de uma variável. Use o operador address-of&, como mostra o seguinte exemplo:

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

    Os campos de objeto são outro exemplo de variáveis móveis que podem ser fixadas.

    Quando o ponteiro inicializado contém o endereço de um campo de objeto ou um elemento de matriz, a instrução fixed garante que o coletor de lixo não realoque ou descarte a instância de objeto que o contém durante a execução do corpo da instrução.

  • Com a instância do tipo que implementa um método chamado GetPinnableReference. Esse método deve retornar uma variável ref para um tipo não gerenciado. Os tipos do .NET System.Span<T> e System.ReadOnlySpan<T> fazem uso desse padrão. Você pode fixar instâncias span, como mostra o exemplo a seguir:

    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
        }
    }
    

    Para obter mais informações, veja a referência de API Span<T>.GetPinnableReference().

  • Com uma cadeia de caracteres, como mostra o exemplo a seguir:

    unsafe
    {
        var message = "Hello!";
        fixed (char* p = message)
        {
            Console.WriteLine(*p);  // output: H
        }
    }
    
  • Com um buffer de tamanho fixo.

É possível alocar memória na pilha, onde ela não está sujeita à coleta de lixo e, portanto, não precisa ser fixada. Para fazer isso, use uma expressão stackalloc.

Você também pode usar a palavra-chave fixed para declarar um buffer de tamanho fixo.

Especificação da linguagem C#

Para obter mais informações, confira as seguintes seções da especificação da linguagem C#:

Confira também