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

Les Variables II

Les fractionnaires
Les chaînes
Les records

Leçon 5 : Eh bien on nʼest pas arrivé !


Lʼimportant nʼest pas dʼaller vite en besogne, mais sachez que lʼassimilation des bases vous fera avancer ultérieurement à pas de géant. En général, les leçons dʼinformatique débutent très vite par un petit programme pour gratifier lʼapprenti et lʼencourager à persévérer. Pour sacrifier à la tradition, choisissez le Runtime Console par lʼintermédiaire du menu Commande et tapez la ligne suivante dans lʼéditeur :

PRINT "Je suis devenu(e) une bête en programmation."

Voilà, cʼest fait ! vous pouvez exécuter votre programme (article Exécuter "Sans titre 1" du menu Commande) ou bien en faire une réelle application Macintosh (article Construire du menu Commande) après avoir sauvegardé votre fichier de code source sur votre disque dur.

Pour lʼinstant, le but que nous poursuivons nʼest pas dʼexpliquer les commandes, ce quʼelles font et comment les exploiter au mieux, mais il sʼagit de comprendre ou plutôt de se faire une représentation des rouages internes qui sont mis en action. Lorsque cette image sʼest formée, lʼensemble devient très cohérent et chaque chose tient bien en place.

Pour résumer, quʼavons-nous appris jusque-là ?

Dans le texte que nous rédigeons (le code source) nous utilisons des noms symboliques pour représenter des valeurs que nous manipulerons avec des instructions composées de commandes ou de fonctions et dʼopérateurs.

Pour les valeurs qui restent fixes tout au long du programme nous sommes avisés quʼil vaut mieux déclarer des constantes portant un nom significatif afin de faciliter la compréhension du code source, tandis que les valeurs qui sont susceptibles de changer seront stockées dans des variables. Les variables occupent plus ou moins de cases en mémoire suivant les valeurs quʼon doit y ranger. Les valeurs quʼon y range sont des octets (des suites de 8 bits) que le Compilateur saura correctement manipuler si on lui indique le type de la variable concernée.

Voici enfin un exemple concret :

_bonus = 10
DIM AS SHORT x, y
x = -4
y = ABS(x) - _bonus


x, y et bonus sont des noms symboliques. x et y sont des variables tandis que _bonus est une constante nommée.

Lʼinstruction _bonus = 10 assigne à la constante la valeur quʼelle représentera tout au long du programme (dans ce programme _bonus vaudra tout le temps 10).

Lʼinstruction DIM AS SHORT x,y indique au Compilateur que les variables x et y vont contenir des valeurs entières (chacune dʼentre elles occupera deux octets qui pourront représenter des valeurs allant de -32768 à +32767)

Lʼinstruction x = -4 range la valeur -4 dans la variable quʼon a choisie dʼappeler x.

La troisième instruction est un peu plus compliquée : dans la variable y sera rangé le résultat dʼun calcul. Comme précédemment indiqué, le signe égal est lʼopérateur dʼassignation du BASIC. La variable qui doit être assignée se trouve toujours à la gauche du signe égal, tandis que la valeur à ranger est à la droite de ce même signe. On emploiera fréquemment le terme « expression numérique » lorsque la partie droite fournit le résultat dʼun calcul. Ici, lʼopération effectuée est une soustraction; vous avez sans doute remarqué lʼopérateur - devant la constante _bonus. Les expressions numériques peuvent devenir très compliquées parce quʼelles peuvent inclure des appels à des fonctions qui font elles-mêmes des calculs et retournent un résultat. Cʼest le cas ici, avec ABS qui est une fonction standard du BASIC. Cette fonction accepte un seul paramètre et retourne une valeur. ABS retourne la valeur absolue du nombre que vous lui passez en paramètre. Si vous lui passez 7 par exemple, elle vous retournera 7, et si vous lui passez -7 elle vous retournera 7 aussi. Dans notre exemple cʼest le contenu de la variable x qui est passé en paramètre à la fonction ABS, et x valant -4 la valeur retournée par la fonction sera donc 4.

Le calcul effectué par lʼinstruction se résumera finalement à ceci :

y = 4 - 10

y se verra donc assigner la valeur -6.

Les fractionnaires
Pour représenter le monde correctement les entiers ne sont pas suffisants, et très souvent on a besoin dʼune plus grande précision. FB propose trois types de variables pour représenter des nombres qui peuvent avoir une partie décimale et une partie fractionnaire. Nous nʼentrerons pas maintenant dans le détail de lʼorganisation interne des octets, mais chacun des types diffère par la quantité de mémoire quʼil nécessite, la plage des valeurs quʼil peut représenter et sa précision.

Le type FIXED est assez peu utilisé, il occupe 4 octets de stockage et peut représenter des valeurs dans la plage -32767.99998 à +32767.99998, il est précis jusquʼà 5 chiffres après la virgule. Une variable de type FIXED a ceci de particulier quʼelle ne possède pas de suffixe identificateur de type, en conséquence, vous ne pouvez déclarer ce type de variable quʼà lʼaide de la commande DIM suivie de la clause AS FIXED.

Notez dès à présent que les nombres utilisés par le langage sont au format anglo-saxon. Ce que nous appelons la virgule sʼécrit avec un point. Nous serions tentés dʼécrire ceci par exemple :

x = 10,3

FB ne comprendra pas ce que vous voulez faire, pour lui, la virgule a une autre signification comme séparer les arguments dʼune fonction par exemple. Dans votre code source, vous devrez écrire ceci à la place :

x = 10.3

Pour nous français, il y a là une difficulté que lʼon apprend vite à maîtriser. La difficulté survient lorsquʼon veut afficher ce type de valeurs, car nous devons bien sûr reformater le nombre en remplaçant le point par une virgule avant de le présenter sur l'écran à lʼutilisateur final de notre application. La difficulté est double, car une conversion similaire doit être opérée dans la direction inverse lorsque les valeurs nous sont fournies par lʼutilisateur ou bien proviennent dʼun fichier externe à notre application. Cependant cette tâche nous sera facilitée à la fois par FutureBASIC et par la Toolbox du Macintosh, mais nous ne nous attarderons pas sur ce problème maintenant.

Les nombres fractionnaires sont le plus souvent représentés avec les types SINGLE (simple précision, suffixe !) et DOUBLE (double précision, suffixe #). On dit que ce sont des nombres à virgule flottante, car le point décimal nʼest pas fixe. Le type DOUBLE est plus précis et peut représenter une plus grande plage de valeurs que le type SINGLE, mais aussi il occupe une plus grande place de stockage en mémoire. Le type SINGLE occupe 4 octets en mémoire tandis que le type DOUBLE possède une étrange particularité : son espace de stockage varie suivant le processeur pour lequel vous compilez votre programme. Lorsque vous compilez pour le 68K (ancien processeur qui équipait les machines dʼApple) il occupe 8 octets, lorsque vous compilez pour le PowerPC, il en occupe 10. Comme on le voit, sur le PowerPC 80 bits sont utilisés pour représenter un nombre. Nous ne rentrerons pas ici dans le détail de lʼarrangement interne des bits, mais il nʼa plus rien à voir avec ce qui a été montré concernant les nombres entiers.

Les chaînes
Le type chaîne (suffixe identificateur $) est utilisé pour représenter une suite de caractères. Le nombre maximum de caractères dʼune variable de ce type est 255. Cela ne vous rappelle-t-il rien ?

Et en effet, cʼest bien la valeur maximale que lʼon peut obtenir avec un octet non signé. Comprendre lʼorganisation interne simplissime dʼune chaîne vous sera utile en de nombreuses occasions. Une chaîne se présente en mémoire comme une suite dʼoctets. Le premier octet indique le nombre de caractères dont la chaîne est constituée, et ce premier octet est suivi par les caractères en question.

Mais quʼest-ce à dire, je croyais que lʼon ne stockait en mémoire que des 1 et des 0, comment peut-on alors avoir des caractères ?

On a commencé à voir peu à peu que lʼorganisation interne des valeurs, des octets et des bits nʼavait que peu de choses à voir avec ce que lʼêtre humain perçoit et croit manipuler. En réalité, les caractères nʼexistent pas en eux-mêmes, la suite dʼoctets dans une chaîne nʼest finalement quʼune suite de nombres.

En fait, notre alphabet a été codifié et à chaque symbole a été attribué une valeur unique représentable avec un octet non signé, et on dispose dʼune table de correspondance. Par exemple, la valeur 65 a été attribuée à la lettre A (notez la majuscule), 66 à la lettre B, etc. Ces codes sont appelés codes ASCII.

Heureusement, il nʼest pas nécessaire de connaître la table des codes ASCII pour manipuler des chaînes de caractères. Sachez toutefois que seuls les premiers 127 éléments de cette table ont été standardisés (les codes et ce quʼils représentent sont identiques sur le Macintosh comme sur le PC, mais au-delà de 127 cela nʼest plus vrai).

Pour se faire une petite idée, imaginez une variable chaîne contenant le texte "Bonjour", pour l'ordinateur ce n'est qu'une suite de bits, ou si vous préférez de 1 et de 0 quelque part en mémoire:

0000011101000010011011110110111001101010011011110111010101110010

Chaque groupe de 8 bits forme un octet dont on peut se figurer la représentation décimale à l'aide des puissances de 2 comme précédemment montré :

7 66 111 110 106 111 117 114

La première valeur est 7 et elle correspond bien au nombre de caractères contenus dans notre chaîne. Bonjour a autant de lettres qu'il y a de jours dans la semaine. Le deuxième octet vaut 66 et représente le code ASCII de la lettre B majuscule; 111 et le code ASCII pour la lettre o minuscule; 110 pour la lettre n minuscule; etc.

Voici la table ASCII des caractères standards : Et voici la table des codes ASCII non-standards telle quʼelle se présente sur le Macintosh aujourdʼhui* :

Une chaîne nʼest donc quʼun octet de longueur suivi du code ASCII des caractères qui la composent. Cet arrangement des octets est appelé chaîne Pascal (du langage de programmation appelé Pascal). Dʼautres langages nʼauront pas nécessairement la même façon de représenter une chaîne de caractères. Par exemple, le langage C ne connaît pas lʼoctet de longueur ; pour ce langage, une chaîne nʼest que la suite des codes ASCII des caractères terminée par le caractère nul (dont le code ASCII vaut zéro). Les chaînes du C, ne sont pas limitées à 255 caractères.

On peut assigner une variable chaîne de la façon suivante:

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


Le texte placé entre guillemets deviendra le contenu de la variable. Le BASIC fournit des fonctions spécialisées pour manipuler les chaînes de caractères, nous les verrons plus loin, mais sachez dès maintenant que le seul opérateur utilisable avec deux variables de type chaîne à lʼexception de lʼassignation est lʼaddition. Lʼopération qui consiste à ajouter deux chaînes pour en former une nouvelle est connue sous le nom de concaténation.

_espace$ = " "
DIM AS STR255 nom, prenom, patronyme

prenom    = "Dominique"
nom       = "Lebrun"
patronyme = "Votre patronyme :" + _espace$ + nom + _espace$ + prenom


Une fois la dernière instruction du programme ci-dessus exécutée, la variable patronyme contiendra la chaîne de caractères suivante : ‟Votre patronyme : Lebrun Dominique”.

Là encore vous devez bien saisir la distinction entre la variable et son contenu : lorsque vous déclarez une variable de type chaîne, un espace est réservé en mémoire par le Compilateur pour contenir les caractères éventuels qui la composeront. Un octet de longueur suivi de 255 octets possibles cela fait au total 256 octets. Même une chaîne vide (avec 0 caractère) occupera la même place en mémoire. Vous le constatez, les chaînes sont plus gourmandes en mémoire que les nombres, car dans le même espace on pourrait loger 64 entiers longs (qui occupent 4 octets chacun) ou encore 128 entiers courts.

FutureBASIC^3 a introduit dans le langage une nouvelle syntaxe inspirée des langages C et Pascal qui traitent les chaînes comme des tableaux de caractères. Auparavant, comme il a déjà été mentionné, on devait utiliser des fonctions spécialisées pour manipuler les chaînes, mais désormais, cette nouvelle syntaxe nous permet dʼexaminer et de modifier individuellement les caractères dʼune chaîne. Par exemple pour connaître le code ASCII du troisième caractère contenu dans une variable chaîne (appelée ci-dessous laChaine) vous pourrez utiliser les crochets :

codeASCII = laChaine[3]

Habituellement, en BASIC, pour connaître la longueur dʼune chaîne, cʼest-à-dire le nombre de caractères qui la composent, on utilise la fonction LEN qui est très souvent sollicitée :

longueurChaine = LEN(laChaine)

Ci-dessus, le résultat de la fonction LEN est stocké dans la variable longueurChaine, mais là encore la syntaxe entre crochets peut être mise à profit en écrivant ceci à la place :

longueurChaine = laChaine[0]

Le premier octet dʼune chaîne Pascal est lʼoctet de longueur indiquant le nombre de caractères quʼelle contient. Lʼindice 0 entre crochets, nous permet dʼexaminer cet octet.

Vous pouvez également assigner les caractères ainsi que la longueur de la chaîne individuellement grâce à cette syntaxe, par exemple :

laChaine[0] = 0

Lʼinstruction ci-dessus assigne à la variable une chaîne de 0 caractère de longueur, cʼest donc une chaîne vide. Lʼéquivalent en BASIC traditionnel serait lʼinstruction suivante :

laChaine = ""

Lʼinstruction qui suit :

laChaine[3] = 65

assigne le code ASCII 65 (qui correspond à la lettre A majuscule) au troisième caractère contenu dans la variable appelée laChaine. Cʼest ici lʼoccasion de présenter une facilité dʼécriture fort appréciable proposée par FutureBASIC. Vous pouvez retrouver le code ASCII dʼun caractère grâce à la syntaxe montrée ci-dessous:

_"A" vaut 65
_"B" vaut 66

etc.

Lʼexemple précédent peut donc sʼécrire dʼune manière plus compréhensible par un être humain, aussi il ne faut pas se priver de cette particularité :

laChaine[3] = _"A"

En BASIC standard, vous écririez pour la même opération:

MID$(laChaine,3) = "A"


Mais il faut noter que les instructions ont tendance à devenir plus difficiles à lire en BASIC traditionnel quand plusieurs fonctions traitant des chaînes sont imbriquées dans une même expression. Par ailleurs, la syntaxe entre crochets produit un code compilé plus compact et plus rapide à l'exécution.

On vient de voir que la longueur maximale dʼune chaîne de caractères ne pouvait excéder 255, il faut donc prêter une attention particulière lorsque lʼon concatène des chaînes pour ne pas dépasser ce maximum autorisé. Très fréquemment, on nʼa pas besoin dʼautant dʼoctets pour mémoriser de lʼinformation, par exemple pour contenir le nom dʼun fichier (sur le Macintosh un nom de fichier ne pouvait dépasser 31 caractères jusquʼà lʼarrivée du nouveau système de fichiers HFS+, où ce nombre est passé à 255, il faut signaler toutefois que la plupart des applications, y compris le Finder dans Mac OS 9, ne gèrent pas encore cet état de fait !), FB^3 propose plusieurs types de chaînes qui diffèrent par leur possibilité de stockage : STR15, STR31, STR63, STR255. Vous avez sans doute remarqué que les tailles utilisées sont des nombres impairs ; en réalité, le nombre indique la quantité maximale de caractères que lʼon pourra stocker dans une variable de ce type, mais pour connaître la quantité de mémoire effectivement occupée, il faut ajouter à ce chiffre lʼoctet de longueur, si bien que lʼespace réellement occupé est toujours un nombre pair dʼoctets. Ce nʼest pas un hasard, car lʼordinateur travaille beaucoup plus efficacement lorsque les variables sont alignées en mémoire sur des adresses paires.

Sachez aussi que vous pouvez réserver une quantité arbitraire dʼoctets (ne dépassant pas 255) lors de la déclaration dʼune chaîne de caractères en utilisant la syntaxe comme montrée dans lʼinstruction suivante :

DIM 7 uneChaine$

Notez que le nombre de caractères est placé juste avant le nom de la variable chaîne que vous voulez déclarer et que ce nom doit avoir le suffixe identificateur de type approprié aux chaînes. Lʼinstruction ci-dessus réserve donc 7 octets pour les éventuels caractères, plus 1 octet de longueur, cela fait 8 octets au total. Lʼalignement des variables sur une frontière paire sera correct. Maintenant, si vous écrivez ceci :

DIM 8 uneChaine$

vous réservez 8 octets pour les caractères et 1 octet de longueur, le total nous donne 9, un chiffre impair. FutureBASIC, dans cette situation, ajoutera un octet pour que la frontière entre les variables soit toujours une valeur paire. 10 octets seront alors effectivement réservés. On appelle cet invité surprise un octet dʼalignement. Si dans lʼimmense majorité des cas vous nʼaurez jamais à vous soucier de ce détail interne, il pourra arriver quʼil prenne de lʼimportance en de rares occasions.

Les variables composées ou records
Jusquʼici les choses ne sont pas trop compliquées, nous nʼavons parlé que de quelques types fondamentaux avec lesquels on peut déjà faire beaucoup de choses, certes, mais très vite lorsquʼon programme, on réalise que ces types de variables ne sont pas suffisants pour décrire des éléments quʼon souhaite manipuler.

Un exemple simple est le rectangle : pour décrire un rectangle on aura besoin de 4 coordonnées - les coordonnées x,y du point situé en haut à gauche et celles du point situé en bas à droite. On peut très bien sʼarranger en créant 4 variables : x1, y1, x2 et y2. Des entiers courts sont généralement suffisants pour y ranger les valeurs quʼon veut y stocker. 4 entiers courts de 2 octets chacun, cela nous fait 8 octets de stockage. Il serait bien pratique dʼavoir ces 8 octets placés consécutivement en mémoire et de nous référer au rectangle au moyen dʼune seule variable. Cʼest exactement de que font les records.

Les records (connus sous le nom de structures dans dʼautres langages) sont un agrégat de variables qui ne sont dʼailleurs pas toute forcément du même type. Ces variables sont donc regroupées sous une même entité. Les records permettent ainsi au programmeur de créer ses propres types de variables.

La définition dʼun type de record est très simple, examinez comment on pourrait définir un type de variable Rectangle :

BEGIN RECORD Rectangle
  DIM y1 AS SHORT
  DIM x1 AS SHORT
  DIM y2 AS SHORT
  DIM x2 AS SHORT
END RECORD


La commande BEGIN RECORD vous permet de donner un nom à votre structure, tandis que la commande END RECORD termine la définition. Entre ces deux commandes, vous déclarez des ‟variables” avec leur type de la même manière quʼil a été montré jusque là.

Rien de plus simple, mais en réalité il ne faut pas sʼy tromper, les diverses déclarations à lʼintérieur de la structure ne sont pas des déclarations de variables en tant que telles. En fait, ici vous déclarez ce quʼon appelle des champs. Donc, les champs dʼun record se déclarent de la même manière que des variables. Comme les variables, les champs dʼun record portent un nom qui les identifie et possèdent un type indiquant la quantité de stockage mémoire pour les valeurs quʼils sont amenés à contenir.

Une fois que votre structure est définie, vous pouvez déclarer des variables possédant ce type. Par exemple :

DIM rect1 AS Rectangle
DIM rect2 AS Rectangle


Les instructions ci-dessus déclarent deux variables (rect1 et rect2) comme étant du type Rectangle.

Pour manipuler les valeurs contenues dans ces variables, vous utiliserez le nom des champs (notez le point qui sépare le nom de la variable, du nom du champ) :

rect1.x1 = 0


La valeur 0 est rangée dans le champ x1 de la variable rect1

rect2.x1 = rect1.x1 + 50

Le champ x1 de la variable rect2 recevra la valeur du champ x1 de la variable rect1 additionnée de 50.

Définir un record revient en fait à définir un type de variable qui peut être composé avec dʼautres types préexistants. Un record peut contenir des champs de différents types y compris des champs qui sont eux-mêmes des records. Exemple :

BEGIN RECORD Objet
  DIM epaisseur AS INT
  DIM contour   AS Rectangle
END RECORD


Pour accéder à une valeur contenue dans le champ contour qui est aussi un record, on pourrait avoir ceci :

DIM unObjet AS Objet
x = unObjet.contour.x1


Notez les points qui séparent les champs.

Lʼespace de stockage pour une variable de ce type est la somme des espaces de stockage de tous les champs qui le composent. Dans lʼexemple ci-dessus, la variable unObjet occuperait la place en mémoire de 6 entiers courts soit 12 octets au total.

Dans FB^3 les records définis par BEGIN RECORD/END RECORD sont appelés ‟vrais” records. FB considère la structure comme un type de variable à part entière. On verra quʼil nʼen est pas de même pour les ‟pseudo” records.

Une fois que vous avez défini une structure, vous pouvez bien sûr dimensionner autant de variables de ce type que votre programme le nécessite.

À lʼinstar des constantes, les records doivent pouvoir être identifiés de manière unique par le Compilateur. Cʼest pourquoi vous ne pouvez avoir deux records portant le même nom dans un même programme. Cependant, vous pouvez avoir plusieurs records différents qui possèdent des champs portant le même nom. Par exemple, vous ne pouvez pas avoir ceci :

BEGIN RECORD
Objet
  DIM epaisseur AS INT
  DIM contour   AS Rectangle
END RECORD

BEGIN RECORD Objet
  DIM couleur AS INT
  DIM largeur AS INT
  DIM hauteur AS INT
END RECORD


Le Compilateur ne saurait pas quelle définition utiliser pour dimensionner une variable de type Objet, aussi refusera-t-il de compiler votre programme si vous commettez cette erreur. Mais, vous pourriez avoir ceci :

BEGIN RECORD Objet
  DIM epaisseur AS INT
  DIM contour   AS Rectangle
END RECORD

BEGIN RECORD Cadre
  DIM contour   AS Rectangle
  DIM epaisseur AS LONG
END RECORD


Deux ‟vrais” records différents peuvent avoir des champs dont les noms sont identiques et qui peuvent représenter des valeurs de types différents.

Dans les anciens BASIC, les structures nʼexistaient pas, on était condamné à déclarer des variables séparées et à les gérer individuellement. Vous trouverez encore beaucoup de morceaux de code écrits pour FutureBASIC qui nʼen font pas usage, mais vous verrez très vite que les structures sont vraiment très commodes pour organiser les données à lʼintérieur de vos programmes.

FutureBASIC agit intelligemment avec les records, par exemple si vous avez deux variables records de la même longueur (occupant la même place en mémoire) vous pouvez assigner en une seule opération le contenu dʼune variable record à une autre.

DIM AS Objet obj1, obj2
obj1 = obj2


Ci-dessus, le contenu de obj2 est copié dans obj1 quelle que soit la taille requise pour les variables de type Objet.

Toutefois, vous ne pouvez pas comparer des variables records entre elles, vous devrez comparer chaque champ de la première variable au champ correspondant de la seconde.

Il faut savoir que les fonctions et les procédures de la Toolbox du Macintosh font un usage très intensif des structures. Cʼest pourquoi il est bon de se familiariser assez vite avec ce concept. La Toolbox déclare donc une quantité impressionnante de ‟records”, et pour sa part, FutureBASIC déclare pour vous ceux qui sont le plus fréquemment utilisés. Par exemple, la structure pour un rectangle est déjà définie comme ceci par la Toolbox :

BEGIN RECORD Rect
  DIM top    AS INT
  DIM left   AS INT
  DIM bottom AS INT
  DIM right  AS INT
END RECORD


Du fait que FutureBASIC définit pour vous un tel record, vous pouvez déclarer une variable de ce type et accéder à ses champs sans avoir plus de travail à fournir. Exemple :

DIM monRectangle AS RECT
monRectangle.top = 10
monRectangle.left = 10
monRectangle.bottom = 50
monRectangle.right = 50


Si vous tentiez de définir la structure RECT dans votre code source, le Compilateur ne manquerait pas de se plaindre en vous signalant que vous essayez de dupliquer une définition. Rien ne vous empêche cependant de définir un record identique et de lʼutiliser partout dans votre code où un record RECT est attendu, par exemple :

BEGIN RECORD Rectangle
  DIM haut   AS INT
  DIM gauche AS INT
  DIM bas    AS INT
  DIM droite AS INT
END RECORD


On verra plus loin, dʼautres avantages à utiliser des ‟vrais” records dans ses programmes.

Les vrais records comme décrits ci-dessus sont apparus avec FutureBASIC^3, mais historiquement, FutureBASIC utilisait des records différents. Beaucoup de programmeurs continuent à utiliser les anciens records, on ne chasse pas aussi vite les habitudes quʼon prend en programmation, c'est d'ailleurs pourquoi il est bon d'en prendre de bonnes dès le départ. Il est probable que ces structures, appelées aujourdʼhui ‟pseudo” records, disparaîtront progressivement au profit des ‟vrais” records. Les ‟pseudo” records sont un peu plus délicats à maintenir.

Un ‟pseudo” record peut être déclaré de la manière suivante :

DIM RECORD Objet
  DIM epaisseur AS INT
  DIM contour   AS RECT
DIM END RECORD .tailleObjet


Lorsque le Compilateur rencontre une telle déclaration dans votre code source, il ne va pas créer un type de variable spécifique et par conséquent vous ne pourrez pas déclarer une variable du type de cette structure avec lʼinstruction suivante :

DIM monObjet AS Objet

Le Compilateur se plaindra en vous signalant que le type pour cette variable nʼa pas encore été défini. Mais alors que fait le Compilateur exactement ?

Il va analyser votre déclaration et en déduire des constantes. Les constantes sont créées en fonction du nom des champs et du stockage réservé pour chaque champ.

Si nous prenons lʼexemple déjà mentionné, après analyse du Compilateur nous aurions :

_epaisseur   = 0
_contour     = 2
_tailleObjet = 6


La valeur des constantes générées correspond au décalage du champ (en octets) par rapport au début de la structure.

Le champ epaisseur étant le premier champ, il se confond avec le début de la structure, il nʼy a donc aucun décalage à opérer pour accéder au champ, dʼoù la valeur 0 attribuée à la constante _epaisseur. En revanche pour accéder au champ contour, les deux octets de stockage (entier court) du champ epaisseur doivent être sautés, cʼest pourquoi la constante _contour se voit attribuer la valeur 2. Si nous avions introduit un autre champ après le champ contour, par exemple, un champ appelé couleur pouvant stocker un entier court, nous aurions alors _couleur = 2 (octets pour epaisseur) + 8 (octets pour contour 4 X 2 entiers courts pour une structure RECT), soit : _couleur = 10.

La dernière constante créée, _tailleObjet, est le total en octets de lʼespace de stockage pour la structure entière.

On déclare une variable de ce type de la manière suivante:

DIM monObjet.tailleObjet

Lorsque vous déclarez une variable comme ci-dessus, le Compilateur va simplement réserver un espace de stockage en mémoire dont la taille correspondra à la constante _tailleObjet.

Bien que le code soit plus lisible ainsi, notez quʼil nʼest pas obligatoire dʼutiliser la constante générée par FutureBASIC et vous auriez pu aussi bien écrire ceci :

DIM monObjet.6

Et lʼon accède aux champs de la manière suivante comme avec les ‟vrais” records :

monObjet.epaisseur      = 10
monObjet.contour.left   = 20
monObjet.contour.top    = 20
monObjet.contour.right  = 100
monObjet.contour.bottom = 200


Il y a une petite subtilité quʼil est bon de connaître : si vous utilisez un caractère de soulignement à la place dʼun point dans lʼinstruction DIM END RECORD, non seulement le Compilateur générera les constantes comme précédemment expliqué, mais aussi il déclarera une variable unique correspondant à cette structure et dont le nom sera le nom du record.

DIM RECORD Objet
  DIM epaisseur AS INT
  DIM contour   AS RECT
DIM END RECORD _tailleObjet

Objet.epaisseur = 10


La variable Objet a été gracieusement créée pour nous par le Compilateur, du fait que nous avons utilisé un caractère de soulignement à la place du point dans lʼinstruction DIM END RECORD.

Si vous avez suivi jusque-là, vous constaterez que le bout de code suivant :

DIM RECORD Objet
  DIM epaisseur AS INT
  DIM contour   AS RECT
DIM END RECORD .tailleObjet

DIM monObjet.tailleObjet


Est en pratique équivalent à écrire ceci :

_epaisseur   = 0
_contour     = 2
_tailleObjet = 6

DIM monObjet.tailleObjet


Vous pouvez bien sûr utiliser lʼune ou lʼautre forme dans vos programmes. Ceci nous montre deux choses cependant : le typage des variables à lʼaide de ‟pseudo” records est un typage très faible, il sʼagit essentiellement dʼune génération de constantes symboliques présentée un peu différemment et le deuxième point en découle, car rappelez-vous que les constantes doivent pouvoir être identifiées de manière unique par le Compilateur, ce qui revient à dire que vous ne pourrez pas avoir deux ‟pseudo” records ayant des champs portant le même nom et que vous ne pourrez pas utiliser non plus des noms déjà réservés pour les constantes prédéfinies par FutureBASIC. Les ‟vrais” records nʼont pas ces deux limitations.

Enfin, pour être complet, il faut signaler lʼexistence dʼune forme spéciale dʼécriture sʼapparentant à la déclaration de records. Cette forme spéciale assez rarement utilisée, est obtenue en faisant appel au recouvrement (ou chevauchement) de variables. Examinez lʼinstruction suivante :

DIM monRectangle.8;0,haut AS INT,gauche AS INT,bas AS INT,droite AS INT

Vous avez noté le point-virgule suivi du zéro ? Que fait le Compilateur lorsquʼil rencontre une telle instruction ?

Lʼinstruction DIM lui indique quʼil doit déclarer des variables. Vous demandez au Compilateur de créer la variable monRectangle qui requiert 8 octets de stockage (monRectangle.8), jusque-là rien de spécial. Le point-virgule suivi du 0 indique au Compilateur de ne pas tenir compte des 8 octets de stockage lorsquʼil va créer les variables suivantes si bien que la variable dénommée haut sera déclarée en mémoire à la même adresse que la variable monRectangle. En réalité, à lʼaide du point-virgule, on indique un décalage (compté en octets) par rapport à lʼadresse de la variable à laquelle il est rattaché (un autre chiffre aurait pu être utilisé à la place de 0). Lorsque 0 est utilisé, les variables monRectangle et haut partagent la même adresse en mémoire.

|monRectangle;0---------------------------------------------------------|
|haut-------------|gauche-----------|bas--------------|droite-----------|
|××××××××|××××××××|××××××××|××××××××|××××××××|××××××××|××××××××|××××××××|
|monRectangle;2---------------------------------------------------------|
|-----------------|haut-------------|gauche-----------|bas--------------|droite-----------|
|××××××××|××××××××|××××××××|××××××××|××××××××|××××××××|××××××××|××××××××|××××××××|××××××××|


Lʼillustration ci-dessus montre comment on peut se figurer la mémoire avec un décalage de 0, puis un décalage de 2 octets.

Les losanges représentent les bits, les groupes de 8 losanges sont séparés entre eux par une barre verticale pour représenter des octets (groupes de 8 bits). Les noms des variables sont aussi séparés entre eux par une barre verticale pour représenter lʼétendue en espace de stockage de chaque variable (un entier court occupe 2 octets).

Le recouvrement de variables permet essentiellement une facilité dʼécriture dans le code. Certaines fonctions de la Toolbox du Macintosh sʼattendent à recevoir une structure en paramètre et plutôt que de créer une variable record et dʼaccéder à ses champs, quelques programmeurs préfèrent utiliser la technique du recouvrement pour manipuler les champs directement au moyen de variables. Examinez lʼexemple suivant :

DIM monRectangle AS RECT;0,haut AS INT,gauche AS INT
                           bas AS INT,droite AS INT
haut   = 10
gauche = 10
bas    = 100
droite = 100

est équivalent à lʼécriture plus traditionnelle, montrée ci-dessous :

DIM monRectangle AS RECT
monRectangle.top    = 10
monRectangle.left   = 10
monRectangle.bottom = 100
monRectangle.right  = 100


Notez également que vous pouvez imbriquer des recouvrements et réaliser des structures relativement complexes.

Lʼécriture ultérieure du code est donc simplifiée avec le recouvrement des variables, mais cette technique a aussi ses inconvénients qui peuvent faire surface si lʼon demande au Compilateur dʼaligner les variables en mémoire sur des frontières adaptées à leur type. Ceci est un peu technique, mais lʼalignement des variables permet au processeur de travailler plus efficacement et plus rapidement.

Encore une fois, la technique du recouvrement nʼest pas très répandue, elle est mentionnée ici, à titre indicatif.



[Precédent] [Table des Matières] [Suivant]
Codes ASCII non-standards
Aujourdʼhui, nous assistons à lʼémergence dʼune autre codification, appelée UNICODE qui a lʼavantage, non seulement de faire une vraie place aux lettres accentuées qui parcourent notre langue, mais aussi aux signes, accents, et caractères spéciaux présents dans les autres langues européennes et dʼailleurs.
© 2000 Pix&Mix
Tous droits réservés

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