Programmation C sharp/Code non vérifié
Le code produit par la compilation d'un programme C# est géré par l'environnement .Net qui effectue diverses vérifications, gère la mémoire en utilisant un ramasse-miette et peut lancer des exceptions en cas d'erreur : référence nulle, divisions par zéro, variable non initialisée, indexation d'un tableau au delà de ses limites.
Le langage C# permet d'utiliser du code non vérifié pour utiliser des pointeurs et d'autres fonctionnalités non sécurisées. Ce mode de fonctionnement est donc à utiliser avec précautions, et à éviter pour les développeurs débutants. |
Le recours à du code non vérifié peut être nécessaire pour utiliser le système d'exploitation, un périphérique accédé par adresse mémoire, ...
Le code non vérifié doit obligatoirement être marqué avec le mot-clé unsafe
. Ce qui permet d'empêcher son exécution dans un contexte non sûr (code provenant d'une source non fiable).
Déclaration
modifierLe mot-clé unsafe peut être ajouté à la déclaration d'une méthode comme dans l'exemple suivant :
public unsafe void Methode()
{
int iData = 10;
int* pData = &iData;
Console.WriteLine("Data contient " + *pData);
Console.WriteLine("Son adresse est " + (int)pData );
}
Il est également possible de l'ajouter pour un bloc d'instruction seul :
public void Methode()
{
int iData = 10;
unsafe
{
int* pData = &iData;
Console.WriteLine("Data contient " + *pData);
Console.WriteLine("Son adresse est " + (int)pData );
}
}
Pointeurs
modifierUn pointeur est un type qui stocke une adresse vers une donnée du type spécifié par le pointeur. La syntaxe d'utilisation est la même que dans les langages C et C++.
Déclaration
modifierLa déclaration d'un pointeur utilise un type suivi du caractère étoile.
Exemple :
int* pEntier; // Pointeur d'entier
Adresse d'une variable
modifierUn pointeur peut recevoir l'adresse d'une variable, en faisant précéder la variable du caractère &
.
Exemple :
int total;
pEntier = &total; // adresse de la variable total
Déréférencer un pointeur
modifierUn pointeur utilisé directement donnera l'adresse de la variable.
Pour utiliser le contenu pointé par le pointeur il faut le déréférencer en le faisant précéder du caractère étoile *
.
Exemple :
*pEntier = 100; // modification de la variable total
Membre d'une classe pointée
modifierPour accéder à un membre d'un objet pointé il est possible d'utiliser la syntaxe suivante :
(*pEntier).ToString(); // accès à la méthode ToString de l'entier pointé
Ou d'utiliser l'opérateur flèche équivalent :
pEntier->ToString(); // accès à la méthode ToString de l'entier pointé
Pointeur et tableau
modifierL'adresse d'un tableau est donnée sans utiliser l'opérateur d'adresse &
. Toutefois, il n'est pas possible de modifier l'adresse du tableau afin d'éviter de perdre l'adresse de début du tableau. Le pointeur doit utiliser le mot-clé fixed
pour obtenir l'adresse d'un tableau.
Exemple :
int[] valeurs = new int[10];
fixed (int* pEntier = valeurs)
for (int iIndex = 0; iIndex < 10; iIndex++)
Console.WriteLine( *(pEntier + iIndex) );
Gestion de la mémoire
modifierLe mode non vérifié permet de modifier le comportement du ramasse-miettes.
Éviter le déplacement par le ramasse-miettes
modifierLe mot clé fixed
sert à éviter qu'un tableau ou un objet ne soit déplacé en mémoire par le ramasse-miettes :
- pour empêcher le déplacement durant l'exécution d'une instruction ou un bloc d'instructions :
fixed (type* pointeur = adresse) instruction
- pour déclarer un tableau de taille fixe (non déplacé en mémoire) :
fixed type[nombre] variable;
Exemple :
protected fixed int[12] jours_par_mois;
Taille d'une variable ou d'un type
modifierL'opérateur sizeof
s'utilise dans un contexte de code non vérifié, comme une fonction renvoyant le nombre d'octets occupés par la variable ou le type spécifié.
Exemple :
int a;
unsafe
{
System.out.println("Taille de a : "+ sizeof(a) +" octets");
System.out.println("Taille d'un entier : "+ sizeof(int) +" octets");
}
Allocation sur la pile
modifierLe mot-clé stackalloc
permet d'allouer un objet ou un tableau sur la pile plutôt que sur le tas. Dans ce cas, cet objet ou tableau n'est pas géré par le ramasse-miettes. Il est donc possible d'utiliser un pointeur sans utiliser le mot-clé fixed
.
Syntaxe : le mot-clé stackalloc
s'utilise à la place du mot-clé new
pour initialiser des pointeurs locaux.
Exemple :
unsafe
{
// allouer 10 entiers sur la pile
int* pEntier = stackalloc int[10];
...
}