fixed, instruction (référence C#)

L’instruction fixed empêche le récupérateur de mémoire de déplacer une variable mobile. L’instruction fixed est uniquement autorisée dans un contexte fixed. Vous pouvez également utiliser le mot clé fixed pour créer des fixed.

L’instruction fixed définit un pointeur vers une variable managée et épingle cette variable pendant l’exécution de l’instruction. Les pointeurs vers des variables managées ne sont utiles que dans un contexte fixed. Sans contexte fixed, le garbage collection peut déplacer les variables de manière imprévisible. Le compilateur C# permet seulement d’assigner un pointeur à une variable managée dans une instruction fixed.

class Point
{
    public int x;
    public int y;
}

unsafe private static void ModifyFixedStorage()
{
    // Variable pt is a managed variable, subject to garbage collection.
    Point pt = new Point();

    // Using fixed allows the address of pt members to be taken,
    // and "pins" pt so that it is not relocated.

    fixed (int* p = &pt.x)
    {
        *p = 1;
    }
}

Vous pouvez initialiser un pointeur à l’aide d’un tableau, d’une chaîne, d’un tampon de taille fixe ou de l’adresse d’une variable. L’exemple suivant montre l’utilisation des adresses de variables, des tableaux et des chaînes :

Point point = new Point();
double[] arr = { 0, 1.5, 2.3, 3.4, 4.0, 5.9 };
string str = "Hello World";

// The following two assignments are equivalent. Each assigns the address
// of the first element in array arr to pointer p.

// You can initialize a pointer by using an array.
fixed (double* p = arr) { /*...*/ }

// You can initialize a pointer by using the address of a variable.
fixed (double* p = &arr[0]) { /*...*/ }

// The following assignment initializes p by using a string.
fixed (char* p = str) { /*...*/ }

// The following assignment is not valid, because str[0] is a char,
// which is a value, not a variable.
//fixed (char* p = &str[0]) { /*...*/ }

À compter de C# 7.3, l’instruction fixed s’applique à d’autres types au-delà des tableaux, chaînes, mémoires tampons de taille fixe ou variables non managées. Tout type qui implémente une méthode nommée GetPinnableReference peut être épinglé. GetPinnableReference doit retourner une variable ref d’un GetPinnableReference. Les types .NET System.Span<T> et System.ReadOnlySpan<T> introduits dans .NET Core 2.0 utilisent ce modèle et peuvent être épinglés. Ceci est illustré dans l'exemple suivant :

unsafe private static void FixedSpanExample()
{
    int[] PascalsTriangle = {
                  1,
                1,  1,
              1,  2,  1,
            1,  3,  3,  1,
          1,  4,  6,  4,  1,
        1,  5,  10, 10, 5,  1
    };

    Span<int> RowFive = new Span<int>(PascalsTriangle, 10, 5);

    fixed (int* ptrToRow = RowFive)
    {
        // Sum the numbers 1,4,6,4,1
        var sum = 0;
        for (int i = 0; i < RowFive.Length; i++)
        {
            sum += *(ptrToRow + i);
        }
        Console.WriteLine(sum);
    }
}

Si vous créez des types qui doivent être inclus dans ce modèle, consultez Span<T>.GetPinnableReference() pour obtenir un exemple d’implémentation du modèle.

Plusieurs pointeurs peuvent être initialisés dans une instruction s’ils sont tous du même type :

fixed (byte* ps = srcarray, pd = dstarray) {...}

Pour initialiser des pointeurs de types différents, imbriquez des instructions fixed, comme indiqué dans l’exemple suivant.

fixed (int* p1 = &point.x)
{
    fixed (double* p2 = &arr[5])
    {
        // Do something with p1 and p2.
    }
}

Une fois que le code de l’instruction est exécuté, toutes les variables épinglées sont libérées et soumises au garbage collection. Par conséquent, ne pointez pas vers ces variables en dehors de l’instruction fixed. La portée des variables déclarées dans l’instruction fixed est limitée à cette instruction, ce qui facilite les choses :

fixed (byte* ps = srcarray, pd = dstarray)
{
   ...
}
// ps and pd are no longer in scope here.

Les pointeurs initialisés dans des instructions fixed sont des variables en lecture seule. Pour modifier la valeur du pointeur, vous devez déclarer une deuxième variable de pointeur et la modifier. La variable déclarée dans l’instruction fixed ne peut pas être modifiée :

fixed (byte* ps = srcarray, pd = dstarray)
{
    byte* pSourceCopy = ps;
    pSourceCopy++; // point to the next element.
    ps++; // invalid: cannot modify ps, as it is declared in the fixed statement.
}

Vous pouvez allouer de la mémoire à la pile, où elle n’est pas soumise au nettoyage de la mémoire et n’a donc pas besoin d’être épinglée. Pour ce faire, utilisez une expression.

spécification du langage C#

Pour plus d’informations, consultez la section Instructions fixes de la spécification du langage C#.

Voir aussi