[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éants. 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 équipaient 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 pour 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 cette limitation.

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
INFO  |  ACQUÉRIR |  PLAN  |  RESSOURCES

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