Q: comment ferais-tu pour "vérifier à la compliation ou au runtime"
En safe-C, il y a 3 types d'objets qu'on peut réserver sur le heap :
a - les objets de taille constante (types simples, struct ou tableaux de longueur constante)
exemple:
donc là, pas de problème, un pointeur vers T sera toujours un pointeur vers T.
b - les objets tableau dynamique
exemple:
float[]^ p = new float[n];
si 'float' occupe 4 bytes, p pointe sur une zone de 4 + n*4 bytes car il y a un header de 4 bytes au début de l'objet heap qui contient la longueur du tableau. p ne pourra pointer que sur des tableaux dynamiques de float;
donc si on fait : p^[n] = 1.2; // n est vérifié grâce au header de p
Faisons un petit exercice académique : si j'ai envie d'agrandir le tableau, disons de le rendre 2 x plus grand :
1 2 3 4 5 6 7 8 9
| float[]^ q;
q = new float[n*2]; // allouer header de 4 bytes + (2*n) éléments
q^[0:n] = p^; // recopier les n premiers éléments (tranche commençant à l'indice 0, de n éléments)
q^[n:n] = {all=> 0.0}; // le reste à zéro (tranche commençant à l'indice n, de n éléments)
free p; // libérer l'ancien tableau
p = q; // maintenant p pointe vers le grand tableau |
Si je veux connaitre la longueur d'un tableau j'utilise l'attribut 'length :
longueur = p^'length; // va chercher la longueur dans le header de l'objet pointé par p
c- les structs avec variantes
1 2 3 4 5 6 7 8 9 10 11 12 13
| struct S (FIG f)
{
int x, y;
switch (f)
{
case RECT:
int long, larg;
case CERCLE:
int rayon;
}
}
S^ p = new S (c); // avec c runtime |
ici p ne peut pointer que sur une struct S.
On réserve un objet heap ayant un header de 4 bytes qui contenant le discriminant (ici c) + les champs de la structure. La taille totale de l'objet dépend de la valeur c à l'exécution. (il y a un tableau constant qui permet au runtime de calculer la taille de S pour chaque valeur de c)
Si on fait :
p^.rayon = 2; // vérifie que le header de p == CERCLE.
C'est limité à ces 3 formes parce que ce sont les plus courantes. Si vous voulez quelque chose de plus inhabituel (par exemple un struct avec un tableau qui suit la struct pour ne consommer qu'une allocation au lieu de deux, par exemple pour stocker les lignes de texte d'un éditeur), il faut travailler "sans filet" avec les unsafe pointers qui sont les mêmes qu'en C.
Tout programme a des sections qui doivent être optimisées à fond : par exemple ce n'est pas très utile de vérifier les indices de tableau lors d'une multiplication de matrices parce que les 2 boucles imbriquées sont tellement simples qu'on 'voit à l'oeil nu' qu'on ne risque pas de sortir du tableau. Pour cela, en Safe-C, on peut utiliser les unsafe pointers du C : donc les opérateurs &, * et -> habituels, ainsi que les [] sur un pointer unsafe.
Exemple:
1 2 3 4 5 6
| #begin unsafe
double d = 1.2;
double p*;
p = &d; // autorisé en section unsafe
*p = 3.4; // sans aucune vérification
#end unsafe |
Pour avoir une idée du coût de ces vérifications, le code pour vérifier l'indice dans :
Une fois qu'on a 'n' dans un registre (par ex: eax), et p^ dans un autre (par ex: esi), on fait :
1 2 3 4 5 6 7
| cmp eax,[esi]
jae error ; >= limite ?
mov [esi+eax*4]4,cte_1.2 ; assignation
.. la suite
error:
int 5; // fatal error |
p.s.: si quelqu'un peut m'expliquer comment on peut formater un message sur le forum ici, j'ai toutes mes lignes collées à gauche quand je publie.
Partager