Skip to content

Instantly share code, notes, and snippets.

@bizouarn
Last active March 31, 2025 13:41
Show Gist options
  • Save bizouarn/7f356d3eadf47c53b754b8049d8acda1 to your computer and use it in GitHub Desktop.
Save bizouarn/7f356d3eadf47c53b754b8049d8acda1 to your computer and use it in GitHub Desktop.
Pourquoi le code unsafe existe-t-il ?

Code unsafe en C#

1. Pourquoi le code unsafe existe-t-il ?

Le mot-clé unsafe en C# permet de manipuler directement la mémoire à l'aide de pointeurs, ce qui est généralement interdit en programmation managée. Il existe pour :

  • Optimiser les performances : Accès direct à la mémoire peut être plus rapide dans certains cas.
  • Interopérabilité : Facilite l'intégration avec du code natif en C/C++.
  • Manipuler des structures mémoire spécifiques : Utile pour le traitement bas-niveau, comme les moteurs de jeu ou certaines applications système.

Cependant, l'utilisation du code unsafe désactive certaines protections offertes par le garbage collector ou le compilateur et peut entraîner des erreurs mémoire difficiles à déboguer.


2. Fonctionnalités disponibles

Avec unsafe, C# permet :

Opérateurs et instructions disponibles

Opérateur/Instruction Utilisation
* Déférencement d'un pointeur.
-> Accès à un membre d'une structure via un pointeur.
[] Indexation d'un pointeur.
& Obtention de l'adresse mémoire d'une variable.
++ et -- Incrémentation et décrémentation des pointeurs.
+ et - Opérations arithmétiques sur les pointeurs.
==, !=, <, >, <=, >= Comparaison de pointeurs.
stackalloc Allocation de mémoire sur la pile.
fixed Fixe temporairement une variable pour obtenir son adresse.

Exemple d'utilisation des pointeurs

unsafe
{
    struct Point { public int X, Y; }
    Point p = new Point { X = 10, Y = 20 };
    Point* ptr = &p;
    Console.WriteLine(ptr->X); // Accès via ->
}

Méthodes de la classe System.Runtime.CompilerServices.Unsafe

  • Unsafe.As<TFrom, TTo>(ref TFrom source) : Effectue un cast sans vérification.
  • Unsafe.Read<T>(void* source) : Lit un objet de la mémoire.
  • Unsafe.Write<T>(void* destination, T value) : Écrit un objet en mémoire.
  • Unsafe.SizeOf<T>() : Retourne la taille en mémoire d'un type.
  • Unsafe.CopyBlock(void* destination, void* source, uint byteCount) : Copie des blocs de mémoire.
int valeur = 42;
float casted = Unsafe.As<int, float>(ref valeur);
Console.WriteLine(casted); // Cast sans conversion (5.9E-44)

3. Exemples concrets d'utilisation

a) Cast unsafe entre types

int valeur = 42;
float casted = Unsafe.As<int, float>(ref valeur);
Console.WriteLine(casted); // Cast sans conversion (5.9E-44)

b) Boucle foreach optimisée sur un tableau

L'utilisation des pointeurs permet de contourner certaines vérifications d'accès aux tableaux, améliorant les performances.

unsafe
{
    int[] array = { 1, 2, 3, 4, 5 };
    fixed (int* ptr = array)
    {
        int* p = ptr;
        for (int i = 0; i < array.Length; i++)
        {
            Console.WriteLine(*(p + i)); // Accès direct sans vérification de bornes
        }
    }
}

c) Manipulation directe de mémoire avec stackalloc

unsafe
{
    int* tableau = stackalloc int[5];
    for (int i = 0; i < 5; i++)
    {
        *(tableau + i) = i * 2;
        Console.WriteLine(*(tableau + i));
    }
}

d) Copie de mémoire avec Unsafe.CopyBlock

using System;
using System.Runtime.CompilerServices;

unsafe
{
    byte[] source = { 1, 2, 3, 4, 5 };
    byte[] destination = new byte[5];
    
    fixed (byte* srcPtr = source, destPtr = destination)
    {
        Unsafe.CopyBlock(destPtr, srcPtr, (uint)source.Length);
    }
    
    Console.WriteLine(string.Join(", ", destination)); // 1, 2, 3, 4, 5
}

e) Accès direct aux champs d'une structure

unsafe
{
    struct Vector2
    {
        public float X;
        public float Y;
    }

    Vector2 vec = new Vector2 { X = 3.5f, Y = 7.2f };
    Vector2* ptr = &vec;
    
    Console.WriteLine($"X: {ptr->X}, Y: {ptr->Y}");
}

f) Modification d'un tableau en mémoire

unsafe
{
    int[] tableau = { 10, 20, 30, 40, 50 };
    fixed (int* ptr = tableau)
    {
        *(ptr + 2) = 100; // Modification de l'élément à l'index 2
    }
    Console.WriteLine(string.Join(", ", tableau)); // 10, 20, 100, 40, 50
}

Conclusion

Le code unsafe en C# est un outil puissant pour les cas nécessitant un accès mémoire direct. Il doit être utilisé avec précaution car il introduit des risques liés à la gestion manuelle de la mémoire, mais il est utile pour des scénarios exigeant des performances optimales ou une interopérabilité avec du code natif.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment