![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
![]() ![]() |
|||||
![]() |
|||||||
![]() |
![]() |
![]() |
![]() |
![]() |
|||
![]() |
![]() |
![]() |
![]() |
||||
![]() |
CHAPITRE
|
APPRENDRE
À PROGRAMMER AVEC FUTUREBASIC
|
NOTES
|
|||||||||||||||||||||||||||||||||||||||||||||||||
Variables IV |
Leçon 7 : Le cauchemar du programmeur Il faut savoir quʼavec les interfaces graphiques en particulier qui agrémentent les ordinateurs dʼaujourdʼhui, des blocs de mémoire sont continuellement alloués, pour, par exemple, stocker des valeurs relatives aux fenêtres, aux boutons et autres champs dʼédition, puis ces blocs sont libérés lorsque les fenêtres sont refermées. La mémoire est très souvent sollicitée et le mécanisme des pointeurs est relativement peu adapté à une gestion efficace de la mémoire. Un autre mécanisme va prendre le relais pour corriger la déficience des pointeurs. Ce mécanisme peut être lʼallié des programmeurs dans la création dʼapplications sophistiquées, tout comme il peut devenir la source de bien des désagréments lorsquʼil est mal utilisé. Lʼidée est la suivante : si les blocs de données pouvaient être réorganisés en mémoire, on pourrait alors éviter la fragmentation en blocs discontinus et utiliser au mieux lʼespace mémoire disponible. Il faut pouvoir cependant garder la trace de lʼadresse de ces blocs amovibles, si lʼon veut accéder aux données quʼils contiennent. Ce résultat est obtenu en créant un pointeur qui contient lʼadresse dʼun autre pointeur. Le pointeur de pointeur est appelé handle et son contenu est alors géré automatiquement par le Memory Manager de la Toolbox. Lorsque le Memory Manager aura besoin de déplacer un bloc en mémoire, il mettra de lui-même à jour la valeur contenue dans le handle pour que celui-ci indique correctement lʼemplacement en mémoire du bloc quʼil est censé référencer. On accède alors aux blocs de manière indirecte en interrogeant dʼabord le handle pour connaître lʼemplacement des données à tout instant. Bien entendu, les risques de ranger des valeurs dans des zones de mémoire erronées sont augmentés, mais il existe des règles à respecter pour éviter les désagréments dʼun plantage qui ne manquerait pas dʼarriver : lorsquʼon crée des variables handles on prend vite lʼhabitude de tester la validité des adresses quʼils contiennent avant de manipuler les données et on « verrouille » très souvent les handles pendant le court instant où on doit y ranger des valeurs afin d'éviter quʼils soient déplacés en mémoire par le Memory Manager avant ou pendant les opérations qui vont modifier les données. De plus, lorsque les données ne sont plus utiles pour le programme, il faut libérer la mémoire occupée afin de permettre aux opérations ultérieures de se dérouler correctement. Un des avantages dans lʼutilisation des handles est de pouvoir gérer des blocs aussi grands que lʼespace en mémoire alloué à votre application le permet. Les blocs de mémoire peuvent être, de surcroît, retaillés au gré des besoins du programme beaucoup plus facilement que les blocs fixes référencés par des pointeurs (les blocs fixes et les blocs amovibles sont créés dans des zones différentes de l'espace mémoire alloué à l'application). . Les handles sont par essence plus difficiles à gérer que des variables traditionnelles. La difficulté est accrue du fait quʼil existe deux types de handles qui, bien que fonctionnant sur des principes quasiment identiques, demandent des traitements différents. Sur le Macintosh certains handles sont gérés par le Memory Manager (gestionnaire de mémoire) et dʼautres le sont pour partie par le Resource Manager (gestionnaire de ressources). Le concept de ressource est un concept essentiel au Macintosh tel que nous lʼavons connu jusquʼici, et nous verrons ultérieurement ce que cela recouvre, il faut juste savoir pour le moment que certains handles peuvent être créés directement par vous et que dʼautres le sont par le Resource Manager associé au Memory Manager. Selon lʼorigine du handle que vous avez à manipuler vous pouvez avoir des traitements différents à effectuer. Les handles sont très puissants, mais leur apparente complexité, a fait qu'on évite génralement de les introduire dans les langages pour débutants. On peut bien sûr écrire avec FutureBASIC des programmes sans déclarer explicitement un seul handle, ce qui ne veut pas dire que votre application nʼen manipulera aucun. Bien au contraire, il est probable que des handles peuplent par dizaines la mémoire allouée à votre application sans que vous en soyez conscient, le Runtime se chargeant de la gestion des handles dont il a besoin pour accomplir ses tâches efficacement. Voici une représentation possible de la mémoire impliquant une variable de type handle : DIM monHandle AS HANDLE monHandle = FN NewString("Hello") Le bout de code ci-dessus déclare une variable handle et appelle la fonction de la Toolbox NewString qui réserve un bloc relogeable en mémoire et y stocke la chaîne Pascal qui lui est passée en paramètre.
LONG IF monHandle autreHandle = FN NewHandle(FN GetHandleSize(monHandle)) LONG IF autreHandle BLOCKMOVE [monHandle],[autreHandle], FN GetHandleSize(monHandle) XELSE PRINT "Mémoire insuffisante !" END IF END IF LONG IF monHandle autreHandle = monHandle LONG IF FN HandToHand(autreHandle) <> _noErr PRINT "Mémoire insuffisante !" END IF END IF En tant que programmeur, vous êtes responsable des blocs que vous allouez au moyen de handles, et vous devez vous assurer de leur libération. Une bonne pratique à adopter est la suivante : aussitôt que vous avez besoin de créer un handle dans une partie de votre programme, trouvez dans votre code source où le bloc devenu inutile doit être libéré et écrivez immédiatement les instructions pour libérer le bloc. Les blocs sont libérés au moyen de la commande DisposeHandle. Cette commande ne remettra pas votre variable à 0 et vous devez le faire vous-même: LONG IF monHandle DisposeHandle(monHandle) monHandle = _nil END IF FutureBASIC propose l'instruction DEF DISPOSEH(monHandle) qui libérera le bloc et remettra la variable passée en paramètre à 0, en supplément elle vérifiera la nature du handle et ne libèrera pas le bloc s'il s'agit d'un handle sur une ressource. Cette commande nécessite que la variable handle soit en mémoire adressable, nous verrons ce que cela veut dire ultérieurement, mais c'est un léger inconvénient. Nous n'avons pas encore vu le concept génial de ressource, mais sachez que les ressources sont des données stockées sur le disque auxquelles votre programme peut accéder et qui peuvent être chargées en mémoire dans des blocs référencés par des handles. La gestion de ces handles diffère quelque peu de celle des handles réguliers. En réalité, les handles peuvent être aisément maîtrisés si l'on respecte un petit nombre de règles : Le respect de ces trois règles très simples vous évitera bien des déconvenues et des frustrations. Traditionnellement, le BASIC ne met pas les handles à la disposition des programmeurs, ces entités étant considérées difficiles à manipuler, FutureBASIC fait cependant une entorse au langage en proposant des routines utilisateurs pour créer, verrouiller, déverrouiller et libérer des blocs relogeables : monHandle = USR _allocRelBlk(taille&) USR _lockBlk(monHandle) USR _unlockBlk(monHandle) USR _disposeBlk(monHandle) Cependant, nous préférerons ici, nous en tenir aux fonctions et procédures de la Toolbox que l'on retrouve identiques dans d'autres langages. Le problème que vous serez amené à rencontrer est lié à la documentation des fonctions disponibles; en effet, la vocation de FutureBASIC n'est pas de dupliquer les informations contenues dans Inside Macintosh (la documentation d'Apple). Cette documentation, qui peut être librement téléchargée depuis le site web d'Apple, est composée de plusieurs dizaines de volumes au format PDF détaillant tous les Managers de la Toolbox, leurs constantes, leurs records et leurs fonctions ainsi que d'importantes indications sur leur utilisation. Lorsque la curiosité ou la nécessité vous conduira à consulter cette documentation, vous comprendrez pourquoi on l'appelle communément la Bible des programmeurs Macintosh. Le mécanisme mis en place dans FutureBASIC^3 vous permet virtuellement, à la différence d'autres langages pour débutants, l'accès à la totalité des fonctions et procédures de la Toolbox comme s'il s'agissait de mots-clés intégrés au langage. Tout comme les pointeurs, les handles peuvent être typés, ce qui nous permet dʼindiquer au Compilateur le type de variable que nous entendons stocker dans les blocs relogeables en mémoire que nous avons réservés DIM unHandle AS HANDLE TO RECT Lʼinstruction ci-dessus déclare une variable de type handle qui pointera sur un bloc de la taille dʼune structure RECT. Notez les deux variantes de lʼinstruction ci-dessus que vous pouvez être amené à rencontrer : DIM unHandle AS HNDL TO RECT DIM unHandle AS ^^RECT unHandle = FN NewHandle(8) Ci-dessus, avec la fonction de la Toolbox NewHandle, on demande au Memory Manager de réserver un bloc de 8 octets et de nous retourner un handle sur ce bloc. Le nombre 8 représente la taille en octets du bloc que vous souhaitez allouer, dans notre exemple, cʼest la taille dʼun record de type RECT. Il nʼest pas toujours pratique de passer une valeur littérale à la fonction NewHandle, car vous pourriez, par exemple, vouloir réserver des blocs pour des records plus compliqués. FutureBASIC fournit une fonction bien utile à laquelle vous passez en paramètre une variable (ou un type de variable) et elle vous retourne la taille en octets occupée par la variable (ou les variables de ce type). Il est plus judicieux dʼutiliser une telle fonction. On écrirait donc plus volontiers ceci : unHandle = FN NewHandle(SIZEOF(RECT)) Ci-dessus, le résultat de la fonction SIZEOF est passé en paramètre à la fonction de la Toolbox NewHandle. Lorsque le handle est créé, on peut accéder alors aux champs du rectangle comme ceci : unHandle..top = 20 unHandle..left = 30 Notez les deux points qui signifient la double indirection. DisposeHandle(unHandle) Ci-dessus, la procédure de la Toolbox DisposeHandle nous permet de libérer la mémoire occupée par le bloc. Attention : dans le code simplifié pour illustrer les propos, aucune précaution n'est prise pour tester la validité du handle. Sachez que, pour une grande part, lʼinstabilité de certains programmes sur Macintosh provient dʼune mauvaise gestion des handles et des problèmes de mémoire que cela engendre. Les containers Pour faciliter la vie aux programmeurs, FutureBASIC^3 a introduit un type de variable un peu spécial : les containers. Les containers (suffixe $$) sont des blocs de mémoire capable de contenir théoriquement jusquʼà 2 gigaoctets de données. Ils peuvent servir, par exemple, à manipuler des chaînes de caractères dʼune taille supérieure à 255 octets tout en autorisant lʼutilisation de fonctions qui sont en principe adaptées au traitement des chaînes Pascal. On peut également, y ranger des valeurs numériques. Les containers sont en réalité des handles déguisés, dont la gestion est simplifiée pour le débutant. Exemple: DIM monContainer AS CONTAINER monContainer = "Une chaîne de caractères" Lʼinstruction ci-dessus range une chaîne dans le container monContainer. monContainer = "" Lʼinstruction ci-dessus est la manière adéquate pour libérer la mémoire occupée par les données du container. monContainer = 10 Lʼinstruction ci-dessus range la valeur 10 dans la variable container. monContainer = monContainer + 20 On peut éventuellement exécuter des opérations avec les valeurs contenues dans un container. Ci-dessus la valeur contenue dans le container sera additionnée de 20. Les containers, comme on le voit, sont très simples à manipuler, en fait le travail de gestion des handles nécessaires pour ce type de variables est réalisé essentiellement par le Runtime. Cependant, les containers souffrent dʼune limitation dont on reparlera plus tard. [Precédent] [Table des Matières] [Suivant] |
{Note} |
![]() |
||
![]() |
||
FutureBASIC est une marque déposée appartenant à Staz Software, Inc et utilisée avec permission. |