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]); // 5Arithmé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 goneTampons 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 stackvoid* 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]); // 99999Quand 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 perfCas 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é
unsafepermet d'utiliser des pointeurs bruts ; le projet doit contenirAllowUnsafeBlocks - 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
stackallocalloue 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>,MemoryMarshaletUnsafedans 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
- Fondamentaux de P/Invoke
- LibraryImport et P/Invoke généré à partir du code source
- Code non sécurisé, pointeurs et tampons de taille fixe
- Interopérabilité COM et wrappers appelables depuis l’environnement d’exécution