Programmation C sharp/Code non vérifié

Programmation C#
Modifier ce modèle

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.

Stop hand nuvola.svg

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éclarationModifier

Le 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 );
    }
}

PointeursModifier

Un 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éclarationModifier

La déclaration d'un pointeur utilise un type suivi du caractère étoile.

Exemple :

int* pEntier; // Pointeur d'entier

Adresse d'une variableModifier

Un 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 pointeurModifier

Un 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éeModifier

Pour 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 tableauModifier

L'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émoireModifier

Le mode non vérifié permet de modifier le comportement du ramasse-miettes.

Éviter le déplacement par le ramasse-miettesModifier

Le 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 typeModifier

L'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 pileModifier

Le 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];
    ...
}