[EN] [IT]
[INFO] [ACQUÉRIR] [PLAN] [RESSOURCES]
CHAPITRE
APPRENDRE À PROGRAMMER AVEC FUTUREBASIC
NOTES

Variables III

Les pointeurs

Leçon 6 : Eh bien ce n’est pas trop tôt !


Les pointeurs

Dans les 2 leçons précédentes, on a vu les types de variables que nous pouvons manipuler avec nos instructions BASIC, mais, vous vous en doutez ce n’est pas encore tout. Lorsque j’ai commencé à faire de la programmation, je lisais des manuels et j’étais quelquefois consterné de ne pas comprendre certains termes que les auteurs assument en général acquis par leurs lecteurs. C’était exactement le cas pour les pointeurs, et j’avais fini par imaginer que lorsque ce terme était compris, on pouvait enfin se revendiquer programmeur. J’avais donc entouré ce terme d’une certaine magie faute de le comprendre. Lorsque ce mystère s’est éclairci, j’ai compris pourquoi les auteurs ne s’attardent pas sur ce concept. Il est en effet plutôt simple.

J’ai pris soin jusqu’ici, de bien faire la distinction entre une variable et son contenu pour que les idées restent bien en place, mais vous verrez qu’en général, on parlera des variables pour se référer à leur contenu (les valeurs qu’elles contiennent) ou aux variables elles-mêmes en tant que containers.

On a vu précédemment que la variable était un espace en mémoire réservé pour contenir des valeurs qui requièrent plus ou moins d’octets. On a vu aussi que cet emplacement en mémoire était en principe fixe et ne changeait pas, seul son contenu pouvait être modifié par nos instructions.

Cependant, Il est parfois très utile de connaître l’adresse en mémoire d’une variable. Les adresses en mémoire peuvent être représentées par des entiers longs (4 octets), pour manipuler ces adresses on utilise un pointeur. Un pointeur n’est autre qu’une variable contenant l’adresse d’une autre variable. Un pointeur occupe 4 octets en mémoire comme les entiers longs.

FutureBASIC dispose d’un raccourci que vous rencontrerez très souvent dans des exemples de code pour signifier l’adresse d’une variable plutôt que son contenu : le symbole @ est utilisé (signifiant ‘at’ [à] comme dans les adresses e-mail). Par exemple :

DIM uneChaine AS STR255
uneChaine = "Je suis une chaîne de caractères"

DIM
adresseChaine AS POINTER
adresseChaine = @uneChaine

Notez qu’en BASIC standard, on écrirait ceci :

adresseChaine = VARPTR(uneChaine)

Cela revient au même, mais il faut bien l’avouer, le symbole @ est bien plus pratique, c’est pourquoi nous l’utiliserons de préférence à la fonction standard VARPTR qui retourne l’adresse de la variable passée en paramètre.

Lorsque vous déclarez une variable pointeur, vous pouvez, si vous le souhaitez, indiquer au Compilateur comment il doit interpréter les données rangées à l’adresse qui est pointée, en spécifiant un type de variable, par exemple comme ceci :

DIM unPointeur AS POINTER TO LONG


Notez tout de suite les variantes, plus souvent utilisées pour l’instruction ci-dessus :

DIM unPointeur AS PTR TO LONG

ou

DIM unPointeur AS ^LONG

Dans l’instruction ci-dessus, vous indiquez au Compilateur que l’adresse qui sera contenue dans la variable unPointeur sera l’adresse d’une variable contenant un entier long. Le type que vous indiquez est arbitraire, en réalité FutureBASIC ne vérifie pas si ce que vous écrivez est exact ou non, c’est vous qui informez le Compilateur sur la taille de la variable qui se trouve en mémoire à l’adresse contenue dans le pointeur.

Lorsqu’on fait ses premiers pas en programmation, on se soucie assez peu de l’adresse des variables, en fait, on s’intéresse avant tout à leur contenu. Les opérateurs du BASIC, font ce qu’ils ont à faire en nous masquant ce qui se passe réellement, par exemple si l’on écrit ceci :

x = y

Cela revient à assigner une valeur à la variable x. Jusque-là ce n’est pas bien sorcier. En réalité, le Compilateur copie le contenu trouvé à l’adresse de la variable y vers l’adresse de la variable x. Pour nous, c’est une façon très simple de changer des données en mémoire, on n’a pas besoin de savoir où se trouve exactement la variable x, ni la variable y.

Vous verrez qu’il y a des circonstances en programmation où il est parfois commode de pouvoir changer directement les valeurs en mémoire. Le BASIC dispose de commandes pour lire et écrire directement des valeurs à des emplacements en mémoire. PEEK et POKE sont les deux commandes qui respectivement vous permettent de lire ou d’écrire des valeurs à une adresse en mémoire. Il y a plusieurs variantes et aussi chacune d’elles dispose d’un raccourci avec FutureBASIC.

PEEK
(ou PEEK BYTE) permet de lire un octet.
Raccourci FB : valeurOctet = |adresseMemoire|

POKE

(ou POKE BYTE) permet d’écrire un octet.
Raccourci : | adresseMemoire,valeurOctet

PEEK WORD

lit un entier court (2 octets).
Raccourci : valeurEntier = {adresseMemoire}

POKE WORD

écrit un entier court (2 octets).
Raccourci : % adresseMemoire,valeurEntier

PEEK LONG

lit un entier long (4 octets).
Raccourci : valeurEntierLong = [adresseMemoire]

POKE LONG

écrit un entier long (4 octets). Raccourci FB : & adresseMemoire,valeurEntierLong

Les programmeurs FutureBASIC utilisent très souvent les raccourcis, aussi, il est bon de les apprendre très rapidement pour comprendre de nombreux morceaux de code que vous serez amené à rencontrer.

On a montré précédemment avec deux techniques différentes comment initialiser une variable chaîne avec une chaîne vide :

La façon classique en BASIC :

DIM uneChaine AS STR255
uneChaine = ""


Une façon nouvelle de faire la même chose avec FutureBASIC^3 et sa syntaxe entre crochets :

uneChaine[0] = 0

Ci-dessus la valeur 0 est assignée à l’octet de longueur, on peut encore faire la même chose en BASIC standard comme ceci :

POKE BYTE VARPTR(uneChaine),0

On range un octet de valeur 0 à l’adresse de la chaîne (qui est l’emplacement en mémoire du premier octet). Et voici, les variations obtenues en utilisant les raccourcis :

POKE VARPTR(uneChaine),0 (BYTE est optionnel, lorsqu’on range un octet)
POKE @uneChaine,0
| @uneChaine,0


Les raccourcis ont tendance à rendre le code un peu ésotérique pour les débutants, mais en fait, ils ne sont pas compliqués à mémoriser. Ils sont fréquemment utilisés par les programmeurs FutureBASIC pour deux raisons : souvent le code à taper est plus court (eh oui, parfois la fainéantise a du bon, car elle vous oblige à chercher les méthodes les plus efficaces pour le moindre effort) et très curieusement vous découvrirez que lorsque vous aurez bien assimilé les raccourcis, ils rendront le code plus facile à lire. La deuxième raison est que le code exécutable généré par le Compilateur est un peu plus compact et un peu plus rapide. De nos jours, cela a moins d’importance, les machines sont très rapides et elles disposent de grandes quantités de mémoire, mais vous verrez que dans certaines circonstances, vous aussi, vous rechercherez le maximum de vitesse dans l’exécution de vos programmes. Peut-être rejoindrez vous un jour ces programmeurs que l'on rencontre souvent avec FutureBASIC qui s'amusent par goût ou par fierté à se lancer des défis afin de produire du code le plus compact et le plus rapide possible.

Dans la plupart des cas, le Compilateur crée les variables en allouant un bloc mémoire de la dimension adéquate lorsqu’il rencontre une instruction DIM. En nous autorisant l’accès aux fonctions de la Toolbox du Macintosh, FutureBASIC^3 nous permet de créer nous-mêmes nos blocs de mémoire comme le fait le Compilateur. Cette opération s’exécute en demandant à la Toolbox de créer un pointeur dont on indique la taille. On a cependant, très peu l’occasion d’utiliser les fonctions relatives aux pointeurs dans la mesure où FutureBASIC se charge très bien des opérations de maintenance par l’intermédiaire des variables que nous lui demandons de créer.

Une variable pointeur contient donc l’adresse d’un bloc en mémoire, mais il faut prêter une attention particulière à ce genre de variable, car en accédant directement à la mémoire on travaille sans filet. En effet, rien ne vous empêche de ranger des valeurs à une adresse quelconque en mémoire, si bien que si votre pointeur contient une adresse erronée, la valeur sera inscrite quand même à l’adresse indiquée et vous pouvez ainsi modifier par inadvertance des valeurs maintenues dans ces blocs pour d’autres variables de votre programme, ce qui donne souvent des résultats inattendus et des erreurs difficiles à corriger comme des blocages du programme sur des instructions innocentes, ou pire encore, si vous accédez à des zones mémoire réservées à d’autres applications ou même au Système, vous serez très susceptible d’expérimenter un crash de la machine.

Un deuxième inconvénient survient lorsqu’on crée soi-même ses pointeurs pour y stocker des valeurs au gré de ses besoins, car les blocs de mémoire que vous réservez ne sont pas rendus disponibles automatiquement une fois que votre code n’en a plus l’utilité et si l’on ne s’en débarrasse pas explicitement, ils finissent par saturer la mémoire inutilement. On est donc obligé de faire soi-même le ménage, en demandant au Memory Manager de libérer la mémoire occupée par les pointeurs devenus inutiles aux besoins du programme. Non seulement cette maintenance est nécessaire, mais la mémoire est utilisée moins efficacement à cause de la fragmentation engendrée lors de la libération des blocs de mémoire. Nous reviendrons ultérieurement sur le Memory Manager et l'importance de son travail.



[Precédent]    [Table des Matières]    [Suivant]
{Note}
  © 2000 Pix&Mix  
  Tous droits réservés
INFO  |  ACQUÉRIR |  PLAN  |  RESSOURCES

  FutureBASIC est une marque déposée appartenant à Staz Software, Inc et utilisée avec permission.