1. HxD Hex Editor 1.6.1 (328 fois)
2. Open Office 2.2.1 (294 fois)
3. Delphi 6 (253 fois)
4. Windows Live Messenger (175 fois)
5. FireFox 2.0.0.12 (135 fois)
03 Sept 2008
Google Chrome : le navigateur 100 % Made In Google... ou presque !
28 Août 2008
Internet Explorer 8 : toutes les nouveautés du navigateur
18 Août 2008
Windows 7 : tout savoir sur le prochain système de Microsoft
13 Août 2008
The Pirate Bay censuré en Italie - L'arrêt de mort du réseau P2P ?
11 Août 2008
Hop : le nouveau téléphone jetable à 15€
Google : le maître des noms de domaines
La nouvelle version de GMail en images !
Barème de rémunération pour les disques durs multimédias
Afficher la date et heure du jour
Alignement de séquences d'ADN
TatNum : gestion des images avec Qt
À votre tour, devenez partenaire de mx-dev.net.
Vous êtes ici : Accueil › Delphi › Tutoriaux › Les chaînes dans Delphi: différents types, gestion mémoire et ref-counting
Auteur : Flo
Catégorie : Manipulation de fichiers
Niveau : Intermédiaire
Posté le : 15 Mai 2007 à 09h51
I.Introduction
Comme vous le savez, Delphi gère lui même toute la partie mémoire des chaînes. Cela évite de passer par les pointeurs de caractères (PChar) et les réallocations de mémoire bien fastidieuses (Prenez un bout de C avec les chaînes, c'est une tout autre affaire vous allez voir).
Dans ce tutoriel, vous allez apprendre, ou ré-apprendre, ou approfondir vos connaissances à ce sujet.
II.Les différents types chaîne
En premier lieu, il faut savoir qu'il n'y a pas qu'un seul type « chaîne » dans Delphi. Sans différentier les chaînes « Ansi » et « Wide », on dénombre trois principales façons de manipuler les chaînes dans Delphi.
A.Les chaînes courtes
D'un point de vue historique, ce type provient tout droit de Turbo Pascal. Il permet de déclarer des chaînes ayant une longueur maximale de 255 caractères.
On les déclare en tant que :
ShortString, dans ce cas, elles occupent 256 octets en mémoire et peuvent contenir 255 caractères (le premier stockant la longueur).
string[n], avec n un entier compris entre 1 et 255. Celles-ci occupent n+1 octets en mémoire et peuvent contenir n caractères.
Pour ces chaînes là, si S est une chaîne, alors Ord(S[0]) = Length(S) = longueur de la chaîne.
B.Les chaînes longues
Si la directive {$H+} est activée, le type string représente une chaîne longue. Dans l'autre cas {$H-}, ce type correspond à ShortString.
Une chaîne longue est en réalité un pointeur, donc une variable de 32 bits (4 octets). Lors de sa déclaration, elle vaut « nil » et n'occupe pas plus de place mémoire. Lorsqu'elle contient des caractères, ceux-ci sont stokés à l'addresse pointée par cette variable.
Il n'y a pas réellement de limite de taille pour les chaînes. La limite est simplement due à la capacité mémoire de la machine. Cependant, un Integer ne pouvant pas contenir un nombre supérieur à 2147483647, la taille des chaînes longues est en réalité limitée à 2 Go. Ce qui laisse une marge très confortable...
Je ne m'étendrait pas plus sur l'occupation mémoire des caractères dans la chaîne, car cela dépend du nombre d'octets pris pour coder un caractère. En effet, pour supporter toutes les langues, Delphi offre la possibilité d'utiliser un codage Unicode (WideString).
Pour plus d'informations sur le sujet, si vous avez l'aide en ligne du BDS installé sur votre ordinateur: ms-help://borland.bds4/bds4ref/html/StringTypes.htm
C.Les types PChar...
Ceux ci présentent une troisième façon de manipuler les chaînes. Cette fois, tout est à la charge du programmeur: création, modification de taille, réallocaitons, etc.
Alors quel intérêt ?
C'est simple, en gérant tout soi même, on va bien plus vite. Ainsi, une fonction effectuant un traitement récurrant sur une chaîne de caractères va bien plus vite (voir ici sur Delphifr.com pour un exemple d'optimisation).
De plus, c'est la seule façon pour envoyer des chaînes aux fonctions de l'API de Windows. Mais, dans ce cas, il suffit souvent de faire un simple transtypage d'une chaîne longue en PChar.
III.Éclaircissements sur la gestion mémoire des chaînes longues
Un peu de code pour commencer :
Si vous récupérez la valeur de Pointer(S), vous allez voir que ce n'est pas l'adresse mémoire du caractère 'B'.
Alors, qu'est-ce que c'est ce bazar ?
En fait, Delphi est intelligent (si si, je vous l'assure). Il stocke des informations sur la chaîne à l'adresse mémoire Pointer(S).
A.Compteur de références
En premier lieu, nous avons le compteur de références. Il indique tout simplement combien de pointeurs pointent vers cette chaîne.
Compliqué ? Pas tant que cela.
Exemple:
var S: string; begin S := 'Bonjour'; end;
Ici, deux pointeurs (S et S1) pointent vers l'adresse mémoire de la chaîne 'Bonjour' et un seul (S2) vers la chaîne 'Bouh !'.
Alors qu'a fait Delphi ?
Et bien, lorsqu'on a fait S1 := S, plutôt que de copier la chaîne dans une autre partie de la mémoire, Delphi a tout simplement fait pointer Pointer(S1) à l'adresse de S.
Et hop ! on a économisé de la mémoire (quelques octets) et du temps (pas de copie inutile).
Maintenant, que se passe-t-il si on modifie la valeur de S ou de S1 ?
Exemple :
var S, S1: string; begin S := 'Bonjour'; S1 := S; S := 'Hello'; end;
Théoriquement, si Delphi modifiait directement l'adresse Pointer(S), cela modifierai aussi la valeur de S1. Eh oui, n'oubliez pas que les deux chaînes pointent vers la même zone mémoire.
Alors Delphi va ruser (puisqu'il est intelligent). Il va allouer un nouveau bloc mémoire et faire pointer S dessus. Comme ça, S1 pointe toujours vers 'Bonjour' tandis que S pointe désormais sur 'Hello'.
Le ref-counting intervient à ce niveau:
Si la chaîne à un compteur de référence à 1, on peut modifier la chaîne sans rien affecter d'autre.
Si le compteur est supérieur à un, il faut obligatoirement allouer un nouveau bloc de mémoire pour ne pas modifier les autres chaînes.
Dernier point: si le compteur de référence d'une chaîne passe à zéro (plus de référence), Delphi libère l'espace mémoire.
C'est pour cela que c'est vraiment utile. Je ne vois mal faire un MyChaine.Free; à chaque fois que j'ai fini d'utiliser une chaîne, ce serait assez fastidieux.
Voila, vous êtes maintenant incollable sur le ref-counting de Delphi.
Sachez juste que c'est le même principe avec les interfaces. (IInterface._AddRef et IInterface._Release).
B.Longueur de la chaîne
La deuxième information stockée avant les caractères, c'est sa taille !
Et oui, la taille que l'on récupère en faisant Length(S).
Pas besoin d'autre explication je pense.
Ah si, une précision: il ne sert donc à rien de stocker dans une variable, puisque l'accès à la longueur de la chaîne est aussi instantané par l'appel à Length() qui, en passant, n'est pas vraiment une réelle fonction (un peu comme Ptr() ou @).
C.Résumé
Donc si on résume, une haine Delphi est stockée dans la mémoire de cette façon là :
|
Information |
Compteur de références |
Longueur de la chaîne |
Caractères |
|
Taille |
4 octets: Integer |
4 octets: Integer |
Taille variable |
|
Lieu de stockage |
Pointer(S) |
Pointer(S) + $04 |
Pointer(S) + $08 |
A noter : Pointer(S) + $08 = Pointer(S[1]), ce qui explique pourquoi il faut écrire S[1] dans un flux et non pas S tout court.
Notez aussi que PChar(S) = Pointer(S[1]), donc le transtypage en PChar ne fait que donner une adresse mémoire (logique).
IV.Conclusion
Vous voilà désormais incollable sur les chaînes dans Delphi. Sachez cependant que ce tutoriel, bien qu'il vous apprenne quand même quelque chose, n'est pas indispensable pour pouvoir coder en Delphi. Pas de panique donc si vous n'avez pas tout saisi.