Types scalaires en Pascal
Un article de Mangue.org, l'encyclopéde libre.
Dans ce cours nous allons apprendre à créer nos types scalaires, ceci permettra d'accroître la lisibilité de nos programme et la maintenance du code sera plus simple.
Les types énumérés
Ce que l'on appelle les types énumérés consiste tout simplement à associer un symbole à différentes valeurs d'entiers.
De tels types sont donc toujours des entiers pour l'ordinateur mais pas pour le programmeur. Dans l'exemple suivant nous avons construit un type jour, l'ordinateur associera à chaque jour une valeur entière qu'il utilisera pour le représenter :
program JoursDeLaSemaine;
(* uses WinCrt; *)
(* definition du type *)
type jour = (lundi, mardi, mercredi, jeudi, vendredi, samedi, dimanche);
(* declaration de la variable *)
var date : jour;
program
for date := lundi to dimanche do
writeln(date)
end.
Les types énumérés n'ont pas de représentation spécifique à l'intérieur de l'ordinateur. Il s'agit simplement de noms différents que l'on donne à des entiers.
C'est pourquoi il est possible d'utiliser la plus part des fonctions définies sur les entiers avec des types énumérés, je pense notamment aux fonctions ord, pred et succ.
ord étant utilisable sur des types énumérés, il est forcément possible d'utiliser la fonction réciproque portant le nom du type lui même et permettant d'associer à un entier la valeur correspondante.Dans notre exemple,
jour(1) retournera donc lundi qui est la première des valeurs possibles pour le type jour.Il est alors possible d'écrire de deux façons différentes les valeurs du type
jour :| lundi | jour(1) |
| mardi | jour(2) |
| mercredi | jour(3) |
| jeudi | jour(4) |
| vendredi | jour(5) |
| samedi | jour(6) |
| dimanche | jour(7) |
| Remarque |
Le type caractère répond aux même exigence que n'importe quel type énuméré. La fonction chr produit le même résultat que char, les caractères ne sont donc rien de plus qu'un type énuméré !
|
Pour des raisons de lisibilité du code source, mais aussi afin de le rendre plus robuste il est préférable de définir explicitement les types énumérés. Pourtant dans certains cas vous pourrez voir des programmes où les types sont anonymes, c'est à dire qu'aucun nom n'y est réellement associé.
Pour l'instant la différence peut vous paraître mince mais vous comprendrez très vite lorsque nous présenterons les fonctions et les procédures quelle est la réelle utilité des énumérations. De plus lorsque votre type reste anonyme il est impossible d'utiliser la fonction réciproque de ord (jour dans notre exemple).
program JoursDeLaSemaine;
(* uses WinCrt; *)
(* declaration de la variable *)
var date : ( lundi, mardi, mercredi, jeudi, vendredi, samedi, dimanche);
program
for date := lundi to dimanche do
writeln(date)
end.
Les types énumérés sont construits sur des entiers (décidément je me répète), rien n'empèche alors au programme de calculer le successeur de dimanche en invoquant une instruction succ(dimanche);
Mais cette valeur n'existe pas dans le type jour, comment le programme va-t-il réagir ? Il n'y a aucun problème de détecter pour le fonctionnement du programme puisqu'il traite ces valeurs comme des entiers. En revanche pour nous celà n'a plus de sens, il n'y a pas de jour suivant dimanche !
Lors de l'écriture de vos programes vous devrez veiller à ce que ceux-cis ne soient pas sujets à ce genre d'erreurs ! La seule méthode que vous connaissez pour l'instant est la vérification systématique en ajoutant des "instructions de débogage" au sein de votre programme... Lisez la page sur les directives de compilation afin de controler ce genre d'erreurs (entre autres).
Les intervalles
Les intervalles sont aussi des types dérivés du type entier. Comme les énumérations, ils permettent de rendre un programme plus facile à comprendre ou à maintenir. Un intervalle est un ensemble de valeurs successives appartenant à un type déjà défini. Ce sont en quelques sortes des cas particuliers des énumérations.
Vous avez déjà vu dans les cours précédents des exemples de type intervalles sans même le savoir. Pensez au byte ou shortint qui appartiennent en fait au type integer.
Un intervalle se définit en donnant ses deux valeurs extrèmes séparés par un ..
Dans l'exemple suivant, nous déclarons un type chiffre que nous utiliserons par la suite, justement pour différencier les chiffres des autres nombres entiers.
program Chiffres;
(* définition du type *)
type chiffre = 0 .. 9;
nombre = integer;
(* byte = 0 .. 255; *)
(* déclaration des variables *)
var nombre1 : nombre;
chiffre1 : chiffre;
(**** début du programme ****)
begin
write('Entrez un nombre : ');
realdn(nombre1);
write('Entrez un chiffre : ');
readln(chiffre1);
writeln('Merci');
end.
| Remarque |
Dans ce programme (et dans ceux qui suivent), l'instruction uses WinCrt; n'apparaît plus. Si vous utilisez le Turbo Pascal Windows, pensez à l'ajouter au début de vos programmes.
|
En principe le compilateur ne devrait pas accepter l'affectation à chiffre1 de valeurs sortant de son intervalle. Mais tout celà dépend encore de la directive de compilation {$R+} que nous verrons en annexe.
En pratique, il convient de prendre un maximum de précautions avec l'utilisation des directives, surtout si vous faites des opérations à l'intérieur du programme sur le type chiffre, rien ne vous empèche de quitter l'intervalle si vous ne spécifiez pas le contraire. Si vous additionnez deux chiffres sans aucun contrôle vous avez malheureusement une probablité non négligeable d'obtenir un résultat supérieur à 9 et de produire une erreur.
Les valeurs de type intervalles ont les mêmes caractéristiques que le type hôte, c'est à dire que tous les opérateurs et fonctions connus pour le type integer peuvent être invoqués pour le type chiffre. En revanche, les nouvelles fonctions et procédure écrites uniquement pour le type chiffre (nous voyons ça dans le cours suivant) ne peuvent pas être utilisées avec le type integer.
Les types énumérés peuvent servir de type hôte pour un intervalle. Reprenons par exemple le type jour défini plus haut et utilisons le pour définir les types jour_ouvrable et jour_repos. Encore une fois pour le moment l'intérêt de telles définitions est limité mais vous en saisirez tous les avantages dans le cours suivant.
program Jours;
(* definition des types *)
type jour = (lundi, mardi, mercredi, jeudi, vendredi, samedi, dimanche);
jour_ouvrable = lundi .. vendredi;
jour_repos = samedi .. dimanche;
(* declaration de la variable *)
var date : jour;
weekend : jour_repos;
boulot : jour_ouvrable;
(**** début du programme ****)
program
(* votre programme utilisant les types définis au dessus ;) *)
end.
Il existe en Pascal un opérateur in permettant de vérifier qu'une valeur soit bien incluse dans un intervalle donné. Son utilisation est assez intuitive, c'est pourquoi je me permet de vous la présenter au travers de cet exemple dans lequel on demande à l'utilisateur de fournir au clavier une lettre :
program UneLettre;
(* déclaration de la variable *)
var Lettre : char;
(**** début du programme principal ****)
begin
repeat
write('Entrez une lettre au clavier : ');
readln(Lettre)
until (Lettre in ['a' .. 'z']);
writeln('Merci :)');
end.
| Danger |
| Attention cet opérateur n'existe pas avec tous les compilateurs. Vérifiez dans l'aide de celui que vous utilisez si il y est fait référence. |
Codage en mémoire des intervalles et types énumérés
Comme nous l'avons vu plus haut les type énumérés sont représentés en associant un entier à chaque valeur du type, c'est d'ailleurs pour cette raison que nous avons la possibilités d'utiliser des fonctions telles que ord, succ, pred ou enfin la fonction portant le nom du type lui même ;)
Le Pascal essai de stocker ces valeurs sur un espace mémoire réduit au minimum, ainsi le type jour défini plus haut sera codé sur un seul entier puisqu'il ne peut pas y avoir plus de valeurs.
| Remarque |
Ainsi, pour le compilateur il existe 256 (28) valeurs différentes pour le type jour.
|
On pourrait penser que les intervalles sont codés de la même manière mais c'est faut. Si un intervalle ne comprends que 3 valeurs il est néanmoins possible de le voir codé sur plus d'un octet.
Un intervalle est codé de manière à ce qu'il soit possible de représenter sa valeur maximale et sa valeur minimale.
Donc si vous créez un type représentant l'intervalle 300 .. 305, les six valeurs différentes de ce type seront quand même codées sur 2 octets afin de pouvoir représenter en mémoire les entiers 300 et 305 qui délimitent cet intervalle.

