Aller au contenu

Programmation C sharp/Code non vérifié

Un livre de Wikilivres.
Programmation C#
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.

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).

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

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++.

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

Exemple :

int* pEntier; // Pointeur d'entier

Adresse d'une variable

[modifier | modifier le wikicode]

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 pointeur

[modifier | modifier le wikicode]

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

[modifier | modifier le wikicode]

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 tableau

[modifier | modifier le wikicode]

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

[modifier | modifier le wikicode]

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

Éviter le déplacement par le ramasse-miettes

[modifier | modifier le wikicode]

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 type

[modifier | modifier le wikicode]

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 pile

[modifier | modifier le wikicode]

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