Obligement - L'Amiga au maximum

Jeudi 25 avril 2024 - 10:51  

Translate

En De Nl Nl
Es Pt It Nl


Rubriques

Actualité (récente)
Actualité (archive)
Comparatifs
Dossiers
Entrevues
Matériel (tests)
Matériel (bidouilles)
Points de vue
En pratique
Programmation
Reportages
Quizz
Tests de jeux
Tests de logiciels
Tests de compilations
Trucs et astuces
Articles divers

Articles in english


Réseaux sociaux

Suivez-nous sur X




Liste des jeux Amiga

0, A, B, C, D, E, F,
G, H, I, J, K, L, M,
N, O, P, Q, R, S, T,
U, V, W, X, Y, Z,
ALL


Trucs et astuces

0, A, B, C, D, E, F,
G, H, I, J, K, L, M,
N, O, P, Q, R, S, T,
U, V, W, X, Y, Z


Glossaire

0, A, B, C, D, E, F,
G, H, I, J, K, L, M,
N, O, P, Q, R, S, T,
U, V, W, X, Y, Z


Galeries

Menu des galeries

BD d'Amiga Spécial
Caricatures Dudai
Caricatures Jet d'ail
Diagrammes de Jay Miner
Images insolites
Fin de jeux (de A à E)
Fin de Jeux (de F à O)
Fin de jeux (de P à Z)
Galerie de Mike Dafunk
Logos d'Obligement
Pubs pour matériels
Systèmes d'exploitation
Trombinoscope Alchimie 7
Vidéos


Téléchargement

Documents
Jeux
Logiciels
Magazines
Divers


Liens

Associations
Jeux
Logiciels
Matériel
Magazines et médias
Pages personnelles
Réparateurs
Revendeurs
Scène démo
Sites de téléchargement
Divers


Partenaires

Annuaire Amiga

Amedia Computer

Relec


A Propos

A propos d'Obligement

A Propos


Contact

David Brunet

Courriel

 


Programmation : Pascal - Les types de base
(Article écrit par Olivier Garrigues et extrait d'Amiga News Tech - mars 1992)


Troisième épisode de notre saga sur le Pascal. Ce mois-ci, nous aborderons les types de base, avec un exemple d'implémentation propre à PCQ : les chaînes de caractères.

En informatique, il existe toujours des concepts prédéfinis, par exemple l'arithmétique sur des octets signés ou non, le système d'exploitation... qui permettent de ne pas refaire le travail (très difficile pour l'arithmétique au niveau de l'électronique). Pour chaque couche (logicielle pour la plupart), on parle d'une nouvelle machine virtuelle. Elle a porté de nouveaux outils, masqué d'autres plus difficiles d'approche. Le Pascal est une machine virtuelle et est un langage typé : nous avons donc des types prédéfinis. Ils sont nécessaires pour que le compilateur puisse appliquer les ordres suivant les propriétés propres à chacun des types. Le plus simple est de vous les présenter :

INTEGER, auquel correspond la représentation des entiers signés codés sur quatre octets (calculs sur 32 bits). Le nombre maximum positif représentable est 2 147 483 647. Ce nombre étant très facile à retenir, vous pouvez utiliser, en cas d'un oubli momentané, la constante prédéfinie MAXINT.

SHORT est une autre représentation des entiers signés. Les variables de ce type sont codées sur deux octets. Théoriquement plus rapide que les variables de type Integer sur notre machine, PCQ les étend à quatre octets au niveau des registres. Le seul avantage de ce type est donc de prendre deux fois moins de place qu'un Integer. L'intervalle des nombres pour le type SHORT est compris entre -32 768 et 32 767. La constante prédéfinie MAXSHORT contient cette valeur.

BYTE est, j'espère ne pas vous surprendre, une représentation des entiers non signés sur un octet. L'intervalle est [0..255] (la notation utilisée ici pour l'intervalle est celle de Pascal). Il n'y pas de constante comme pour les deux premiers types.

Les trois types présentés ci-dessus sont considérés comme compatibles entre eux : une variable d'un de ces types pourra être affectée à une autre sans prise en compte de son type si celui-ci est un cité plus haut. Nous sommes donc en présence d'un irrespect caractérisé du typage, dans un but d'occupation de zone mémoire et de compatibilité avec les standards de notre bécane (octet, mot, mot long). Hélas, aucun test de dépassement n'est fait. Donc, si vous tapez le programme suivant :

Program Octet_Mot_LongMot;
var 
	i:integer; { 4 octets }
	s:short;  { 2 octets }
	b:byte;	{ 1 octets }

BEGIN
i:=40000; { Nombre plus grand qu'une valeur Short }
s:=i;     { Une vilaine affectation } 
b:=i;     { Plus méchante qu'un Goto }
writeln(' i=',i,' s=',s,' b=',b)
          { Pour voir les dégâts }
END.

Vous obtenez le résultat suivant :

i= 40000 s= -25536 b= 64

Un joli effet de bord, plus difficile à trouver dans de nombreux calculs. Alors un conseil : pour des valeurs difficiles à quantifier, utilisez des entiers (INTEGER).

CHAR est le type permettant de stocker un caractère et d'interpréter sa valeur comme tel et non comme un nombre (vous savez que tout, dans un ordinateur, est représenté par des nombres). Il prend un octet en mémoire.

BOOLEAN est le type qui dit "vrai" ou "faux", plus exactement "TRUE" ou "FALSE". Ainsi, nous avons la possibilité de calculer des expressions de la logique de Boole (Boole : 1815-1864).

Les énumérations sont une catégorie de type qui permet une correspondance entre des nombres et une représentation formelle de différents états d'un objet. Un exemple : le feu tricolore à trois états (vert, orange et rouge) ; en Pascal, on écrit :

VAR feu:(vert, orange, rouge);

Vert vaudra ici 0, orange, 1 et rouge, 2. Ainsi, nous pouvons comparer des variables d'une même énumération. Remarquez que l'ordre indique le sens de comparaison. A noter qu'il ne faut pas déclarer deux fois la même énumération sans créer un type propre (ce que nous aborderons au moment de la déclaration de types).

Program Essai_Sur_Enumeration;

var 
	i,j,l:(vert,orange,rouge);
{ déclaration avec le fameux type feux tricolore }
BEGIN
	i:=vert; { Affectation direct } 
	j:=orange; { Idem }

	l:=succ(j); 
{ Utilisation d'un fonction particulière au Scalaire, 
  qui donne le successeur de la valeur passée en argument }

	writeln('l\'affirmation : \"i est inférieur à l\" est ',i

REAL est le type qui permet d'utiliser l'implémentation des réels au format FFP (Fast Flotting Point). Cela nous ouvre les portes des applications scientifiques. La méthode de stockage prend autant de mémoire qu'un entier de type INTEGER (quatre octets).

Les sept types ci-dessus ont la propriété d'être scalaires, c'est-à-dire qu'ils possèdent toujours un successeur (même s'il peut sembler illogique). De plus, il existe un ordre total : on peut toujours comparer deux valeurs de même type. Toutefois, puisque la mémoire allouée à un type est finie, les valeurs sont des modulos (reste d'une division entière) de la valeur réellement indiquée. Un exemple pour illustrer ceci :

Program Valeurs;
{ les valeurs indiquées ne 
  sont pas celles réellement stockées }
Var 
	i:integer;
	s:short;
	b:byte;
{ les réels ayant une implémentation
  particulière, un exemple ne serait
  pas très explicite (méfiez-vous des
  réels !) }
Begin

{ remarquez que tous les nombres afféctés 
  dépassent largement la borne supérieure des
  intervalles respectifs de chaque type }

i:=3_000_000_000;

{ j'utilise une facilité de PCQ qui permet 
  de séparer les chiffres d'un nombre par
  le signe "_", merci encore Patrick }
 
s:=50_000;
b:=300;
writeln('i = ',i,' s = ',s,' b = ',b);

{ si vous avez les mêmes nombres que ceux 
  de dessus, votre implémentation est 
  supérieure à PCQ. }

end.

{ Et pourtant, aucune erreur de compilation n'est fournie par PCQ }

Encore un effet de bord qui, lui, provient de l'implémentation du compilateur.

Pour tous les types arithmétiques (INTEGER, SHORT, BYTE, REAL), il existe des opérations mathématiques standards, comme l'addition, la soustraction, la multiplication et la division, et pour les entiers seulement, le modulo (MOD) et la division entière (DIV). La priorité des opérateurs est normalement respectée (au moins pour les quatre premiers opérateurs). Pour plus de sûreté, vous pouvez utiliser les parenthèses. Voici un petit exemple bête pour se clarifier les idées.

Program Arithmetique;
{ utilisation des opérateurs classiques sur
  plusieurs types }

Var 
	i,j : integer;
	s,t : short;
	b,c : byte;
	x,y : real;

BEGIN
writeln ('Travail sur les entiers : ');
i:= 110 * 44; 
{ multiplication : attention au dépassement 
  de capacité }
writeln (' i = ',i);
j:= 115 + 45; 
{ addition }
writeln (' j = ',j);
writeln (' i divisé par j = ', i div j); 
{ division entière }
{ remarquez que l'opération se fait directement sans
  utiliser une variable intermédiaire }
writeln (' i modulo j     = ', i mod j); 
{ reste }
writeln (' s divisé par t = ', i / j);
{ division : ici le résultat sera toujours réel}
writeln;

writeln ('Travail sur les entiers courts : ');
s:= 10 * (-4);
{ utilisation du moins unaire }
writeln (' s = ',s);
t:= 15 + 40;
writeln (' t = ',t);
writeln (' s divisé par t = ', s div t);
writeln (' s modulo t     = ', s mod t);
writeln (' s divisé par t = ', s / t);
writeln;

writeln ('Travail sur les octets : ');
b:= 10 * 25;
writeln (' b = ',b);
c:= 15 - 10;
{ soustraction }
writeln (' c = ',c);
writeln (' b divisé par c = ', b div c);
writeln (' b modulo c     = ', b mod c);
writeln (' b divisé par c = ', b / c);
writeln;

writeln ('Travail sur les réels : ');
x:= 10.0 + 4.3; 
{ remarquez que le point-zéro ".0"
  est nécessaire pour que le compilateur
  interpréte les nombres sans virgule
  comme des réels }
writeln (' x = ',x);
y:= 15.0 * 40.7;
writeln (' y = ',y);
writeln (' x divisé par c = ', x / y);
END.


Si vous avez regardé la documentation de PCQ, il reste trois types de base :

Address : c'est aussi un type scalaire comme INTEGER. Il permet d'indiquer une adresse-mémoire. Sa valeur est l'adresse d'un octet, d'un mot ou d'un long mot. Ce type est le type pointeur le plus général (les pointeurs seront étudiés au moment des constructeurs de types). Un exemple direct, pas très propre, mais facile à implémenter, est l'accès aux registres de couleurs du matériel.

Program Couleurs_Pas_Propre;
{ il permet de modifier le registre
  COUL0 pendant un très court moment }
Var 
	Coul0 : address;
	i:short;

BEGIN
Coul0 :=address($DFF180);

{ addresse de la couleur 0, j'utilise un 
  cast (un changement de type) car $DFF180
  est de type INTEGER et Coul0 de type 
  ADDRESS. }

for i:=1 to 1000 do
{ le mot "For" indique une répétition (une boucle),
  ici 1000 fois l'affectation suivante :}
   
	Coul0^:=i; 
{ écriture d'un mot dans le registre,
  remarquez le "^" indiquant que c'est
  à l'adresse indiquée par la valeur
  de coul0 que la valeur de i doit
  être affectée }
END. 
 

Cette méthode n'est toutefois pas du tout recommandable. Je tiens à préciser qu'il faut respecter le système d'exploitation !

Text : avec ce type, on touche au système de gestion de fichiers, chose que nous ne ferons pas avant longtemps car, bien que simplifié en Pascal, il nous faut d'autres connaissances. Il sert pour la gestion de fichiers au format ASCII (comme, par exemple, une fenêtre Shell).

Ces deux types ne sont pas des types prédéfinis standards du Pascal, mais ils existent et permettent de simplifier certaines approches de la machine.

Le dernier type a une implémentation différente en PCQ de celle des autres compilateurs Pascal. Je vais donc vous décrire le fameux mais néanmoins folklorique type STRING.

L'un des problèmes de Pascal est justement son imprécision sur l'implémentation du type chaîne de caractères. Patrick Quaid (auteur de PCQ) utilise deux sortes de chaînes de caractères : la première est en fait un tableau, la seconde est ce que l'on nomme l'indirection. Elle correspond au type STRING de PCQ.

On ne peut pas utiliser les opérateurs classiques que l'on rencontre dans d'autres Pascal : concaténation, reproductions multiples... Mais l'implémentation est faite sur la base des chaînes de caractères dans le langage C. Une variable de type STRING n'est autre qu'un pointeur sur une zone de mémoire (en fait un tableau de caractères). Celle-ci est particulière. Elle contient tous les caractères et se termine par un caractère spécial dont la valeur équivaut à 0.

Plusieurs points sont à éclaircir :

1. Un pointeur est une variable qui désigne exclusivement un seul type d'objet, c'est-à-dire qu'il a comme valeur l'adresse en mémoire de l'objet sur lequel il pointe. D'autres explications, avec des exemples, viendront plus tard dans le chapitre sur les constructeurs de types. Dans le cas présent, nous avons un pointeur sur des variables de type CHAR.

2. Un tableau est une zone de mémoire continue dont la longueur est fixe et qui ne contient que le même type d'éléments. Il peut être considéré comme une application d'un sous-ensemble fini de N, vers les éléments contenus dans cette zone mémoire. On déclare un tableau avec le constructeur de type ARRAY.

3. Comme je l'ai précisé pour les variables de type CHAR, ils sont codés sous forme numérique sur un octet (convention ASCII étendue), le caractère NUL (dont la représentation est 0) est utilisé comme marque de fin de chaîne

4. Il faut tout de suite bien différencier la longueur d'une chaîne et la longueur du tableau qui contient la chaîne ; ou plus généralement, différencier le contenu du contenant. La séquence de caractères qui représente la chaîne, doit être plus petite que le tableau contenant celle-ci, sinon la chaîne "mangerait" de l'espace qui pourrait être important et, donc, provoquer une erreur (Guru !).

Comment distinguer les constantes chaînes de caractères et les tableaux de caractères ? Par l'utilisation des délimiteurs : si l'on utilise les guillemets ("), nous aurons une chaîne de type STRING, si nous utilisons les apostrophes ('), nous aurons un tableau de caractères. Cette distinction n'est utile que dans le cas d'appel de procédures implémentées uniquement que pour l'un de ces deux types. Par exemple, la procédure WRITE accepte les deux types mais pas la fonction STRLEN, qui a besoin d'une variable de type STRING. Un petit exemple :

Program Les_Chaines;

{ Comment déclarer des constantes chaines 
  sans utilisation de variables }

BEGIN
Writeln ('Cette chaine de caractères est un tableau');

Writeln ("\aCelle-ci est une STRING\navec des caractères d'échappp\bement");

{ remarquez les caractères d'échappement introduit par "\" }

END. { un peu court non ?}


[Retour en haut] / [Retour aux articles] [Article précédent] / [Article suivant]