0Pricing
C# Academy · Leçon

Code non sécurisé, pointeurs et tampons de taille fixe

Utilisez le mot-clé unsafe, manipulez des pointeurs, épinglez la mémoire managée avec fixed et accédez aux tampons de taille fixe dans les structures.

Code non sécurisé, pointeurs et tampons de taille fixe est une leçon C# Academy gratuite sur CoddyKit. Ceci est la leçon 3 sur 4. Tu peux lire la leçon complète ci-dessous gratuitement — puis la pratiquer en direct dans le navigateur avec un éditeur de code intégré et un tuteur IA 24/7. Elle fait partie du parcours d'apprentissage C# Academy, et ta progression se synchronise sur le web et l'application CoddyKit. Le cours C# Academy comprend 4 leçons au total.

Qu'est-ce que le code unsafe ?

Le mot-clé C# unsafe permet de manipuler directement la mémoire : pointeurs bruts, arithmétique des pointeurs et tampons de taille fixe. Il contourne les garanties de sécurité du GC. Activez-le avec <AllowUnsafeBlocks>true</AllowUnsafeBlocks> dans votre fichier projet.

// Must add to .csproj:
// <AllowUnsafeBlocks>true</AllowUnsafeBlocks>

// Unsafe blocks can appear inside methods:
unsafe
{
    int x = 42;
    int* ptr = &x;          // get address of x
    Console.WriteLine(*ptr); // dereference — prints 42
    *ptr = 100;
    Console.WriteLine(x);    // 100 — x was mutated via pointer
}

Types de pointeurs en C#

La syntaxe des pointeurs ressemble à celle de C/C++ : T* est un pointeur vers T. Vous pouvez déclarer des pointeurs vers des types valeur non managés (int, double, structures sans champs de référence). Les pointeurs vers des types managés ne sont pas autorisés.

unsafe
{
    int    i = 10;
    double d = 3.14;

    int*    ip = &i;
    double* dp = &d;

    // Dereference with *
    Console.WriteLine(*ip); // 10

    // Pointer arithmetic — move to next int in memory
    int[] arr = { 1, 2, 3 };
    fixed (int* p = arr)
    {
        Console.WriteLine(*(p + 0)); // 1
        Console.WriteLine(*(p + 1)); // 2
        Console.WriteLine(*(p + 2)); // 3
    }
}

L'instruction fixed

Le GC peut déplacer les objets managés. Pour obtenir l'adresse d'un objet managé, vous devez l'épingler avec fixed. Le GC ne déplacera pas l'objet pendant toute la durée du bloc fixed.

byte[] buffer = new byte[256];

unsafe
{
    fixed (byte* pBuf = buffer)
    {
        // pBuf is valid only inside this block
        // GC won't relocate 'buffer' here
        for (int i = 0; i < buffer.Length; i++)
            pBuf[i] = (byte)i;
    }
    // After 'fixed', GC can move 'buffer' again
}

Console.WriteLine(buffer[5]); // 5

Arithmétique des pointeurs

Vous pouvez additionner ou soustraire des entiers à des pointeurs. Ajouter 1 à un int* le fait avancer de 4 octets (sizeof int). C'est la base des opérations rapides sur de grandes quantités de mémoire.

unsafe
{
    int[] data = { 10, 20, 30, 40, 50 };
    fixed (int* start = data)
    {
        int* p = start;
        long sum = 0;
        for (int i = 0; i < data.Length; i++)
        {
            sum += *p;
            p++;    // advance by sizeof(int) = 4 bytes
        }
        Console.WriteLine(sum); // 150

        // Or with index syntax:
        Console.WriteLine(start[2]); // 30
    }
}

stackalloc : allocation sur la pile

stackalloc alloue un bloc de mémoire sur la pile, et non sur le tas. Aucune pression sur le GC et aucun épinglage nécessaire. L'allocation est limitée à la trame de pile de la méthode actuelle ; la mémoire est libérée automatiquement lorsque la méthode retourne.

// Stack-allocated buffer — zero heap allocation
Span<int> buffer = stackalloc int[128]; // safe Span wrapper
buffer.Fill(0);
buffer[0] = 42;
Console.WriteLine(buffer[0]); // 42

// Or raw pointer form (requires unsafe):
unsafe
{
    int* raw = stackalloc int[128];
    raw[0] = 99;
    Console.WriteLine(raw[0]); // 99
}
// Stack frame popped — memory gone

Tampons de taille fixe dans les structures

Un tampon de taille fixe intègre directement un tableau de longueur fixe dans une structure : aucune allocation sur le tas ni pointeur supplémentaire. Utilisez le modificateur fixed à l'intérieur d'une structure déclarée dans un contexte unsafe.

unsafe struct NetworkPacket
{
    public int  Length;
    public byte Command;
    public fixed byte Payload[256]; // 256 bytes inline in the struct
}

unsafe
{
    NetworkPacket pkt;
    pkt.Length  = 10;
    pkt.Command = 0x01;

    // Fill payload inline — no heap allocation
    for (int i = 0; i < 10; i++)
        pkt.Payload[i] = (byte)i;

    Console.WriteLine(pkt.Payload[5]); // 5
}
// sizeof(NetworkPacket) = 4 + 1 + 256 = ~261 bytes on stack

void* et conversions de type

Un void* est un pointeur sans type, utile pour les opérations génériques sur la mémoire. Vous devez le convertir en pointeur typé avant de le déréférencer. L'opérateur sizeof(T) fonctionne sur les types non managés dans un contexte unsafe.

unsafe
{
    int value = 42;
    void* vp = &value;      // typeless pointer
    int*  ip = (int*)vp;    // cast back to int*
    Console.WriteLine(*ip); // 42

    // sizeof works on unmanaged types
    Console.WriteLine(sizeof(int));    // 4
    Console.WriteLine(sizeof(double)); // 8
    Console.WriteLine(sizeof(long));   // 8
}

MemoryMarshal et la classe Unsafe

System.Runtime.CompilerServices.Unsafe et System.Runtime.InteropServices.MemoryMarshal fournissent des alternatives sûres, qui n'utilisent pas le mot-clé, pour de nombreuses opérations de bas niveau. Elles sont compatibles avec Span et utilisables sans le mot-clé unsafe.

using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;

// Reinterpret a Span<byte> as Span<int> — no copy, no unsafe keyword
byte[] raw = new byte[16];
Span<int> ints = MemoryMarshal.Cast<byte, int>(raw);
ints[0] = 12345678;
Console.WriteLine(ints[0]); // 12345678

// Unsafe.As<,> — reinterpret reference type (advanced)
ref int first = ref MemoryMarshal.GetReference(ints);
Unsafe.Add(ref first, 1) = 99999;
Console.WriteLine(ints[1]); // 99999

Quand utiliser (ou ne pas utiliser) unsafe

N'utilisez du code unsafe que lorsqu'il existe un besoin clair de performances et aucune alternative sûre. Limitez au maximum la surface unsafe : isolez-la dans des méthodes d'assistance privées ou des types dédiés. Écrivez des tests exhaustifs et documentez vos hypothèses.

// GOOD: narrow unsafe scope
public static unsafe int SumBytes(ReadOnlySpan<byte> data)
{
    int total = 0;
    fixed (byte* p = data)
    {
        byte* end = p + data.Length;
        for (byte* cur = p; cur < end; cur++)
            total += *cur;
    }
    return total;
}

// BETTER for modern code: use SIMD via Vector<T> or hardware intrinsics
// which stay in managed code but still achieve native-level perf

Cas concret : analyser un protocole binaire

Les pointeurs unsafe et les tampons de taille fixe sont particulièrement adaptés à l'analyse de protocoles binaires lorsque la disposition de la structure doit correspondre exactement à un format filaire. La structure peut être convertie directement depuis un tampon d'octets, sans aucune copie.

[StructLayout(LayoutKind.Sequential, Pack = 1)]
unsafe struct MessageHeader
{
    public uint  Magic;        // 4 bytes
    public ushort Version;    // 2 bytes
    public ushort PayloadLen; // 2 bytes
    public fixed byte Id[16]; // 16 bytes GUID inline
}

unsafe ReadOnlySpan<byte> SerializeHeader(MessageHeader hdr)
{
    // Cast struct directly to bytes — zero copy
    return new ReadOnlySpan<byte>(&hdr, sizeof(MessageHeader));
}

unsafe MessageHeader ParseHeader(ReadOnlySpan<byte> buf)
{
    fixed (byte* p = buf)
        return *(MessageHeader*)p; // reinterpret cast
}

Vérification rapide

Pourquoi l'instruction fixed est-elle nécessaire pour obtenir l'adresse d'un objet managé ?

Récapitulatif : code unsafe, pointeurs et tampons fixes

Points essentiels :

  • Le mot-clé unsafe permet d'utiliser des pointeurs bruts ; le projet doit contenir AllowUnsafeBlocks
  • L'instruction fixed épingle les objets managés afin que le GC ne les déplace pas
  • L'arithmétique des pointeurs avance selon la taille de l'élément, et non en octets
  • stackalloc alloue sur la pile : aucune pression sur le GC et libération à la sortie de la méthode
  • Les tampons de taille fixe (fixed byte Payload[N]) intègrent les tableaux directement dans les structures
  • Privilégiez la classe Span<T>, MemoryMarshal et Unsafe dans la plupart des situations

Questions Fréquemment Posées

La leçon « Code non sécurisé, pointeurs et tampons de taille fixe » est-elle gratuite ?

Oui — le texte complet de « Code non sécurisé, pointeurs et tampons de taille fixe » est gratuit à lire ici sur le web. Pour la pratiquer de manière interactive (un éditeur de code intégré et un tuteur IA 24/7) et déverrouiller le reste du cours C# Academy, passe à CoddyKit PRO. Le cours C# Academy comprend 4 leçons au total.

Qu'est-ce que j'apprendrai dans « Code non sécurisé, pointeurs et tampons de taille fixe » ?

Utilisez le mot-clé unsafe, manipulez des pointeurs, épinglez la mémoire managée avec fixed et accédez aux tampons de taille fixe dans les structures. Tu pratiques C# Academy avec du code pratique que tu exécutes directement dans le navigateur, et un tuteur IA 24/7 répond à tes questions au fur et à mesure que tu avances dans la leçon.

Dois-je avoir de l'expérience pour commencer C# Academy ?

Aucune expérience préalable n'est requise. C# Academy sur CoddyKit est structuré pour les débutants jusqu'aux apprenants avancés, donc tu peux commencer ici ou depuis le début et avancer à ton rythme. Ceci est la leçon 3 sur 4.

Combien de temps prend la leçon « Code non sécurisé, pointeurs et tampons de taille fixe » ?

La plupart des leçons CoddyKit prennent environ 5–10 minutes. Chacune est courte et interactive, tu progresses régulièrement et tu repiques exactement où tu t'es arrêté sur le web et l'app.

Peux-tu écrire et exécuter du code dans cette leçon C# Academy ?

Oui. Chaque leçon C# Academy inclut un éditeur de code intégré, tu écris et exécutes du vrai code directement dans ton navigateur et tu reçois des retours IA instantanés — aucune configuration locale requise.

Toutes les leçons de ce cours

  1. Fondamentaux de P/Invoke
  2. LibraryImport et P/Invoke généré à partir du code source
  3. Code non sécurisé, pointeurs et tampons de taille fixe
  4. Interopérabilité COM et wrappers appelables depuis l’environnement d’exécution
← Retour à C# Academy