Suivez-nous sur X
|
|
|
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
|
|
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
|
|
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
|
|
A propos d'Obligement
|
|
David Brunet
|
|
|
|
Programmation : Amiga E - la mémoire et les pointeurs
(Article écrit par Yann Armand et Pierre Girard et extrait d'Amiga News - octobre 1995)
|
|
Nous devinons votre frustration à la lecture de l'article précédant. En effet, le
traitement des arguments n'était pas expliqué, mais les pages d'Amiga News ne sont pas extensibles à l'infini. Réparons donc
cette infamie à travers l'explication de la mémoire et des pointeurs.
La mémoire
Comme tous ses homologues à puces, l'Amiga (et non pas le chien) possède une mémoire (le chien aussi, c'est vrai). Celle-ci est
essentielle car elle permet d'exploiter aussi bien les programmes que les données. En ce qui nous concerne, elle sert
essentiellement à stocker temporairement les données que nous manipulons.
La mémoire est constituée de cases mémoire repérées par une adresse. Elle peut être comparée à un gros livre dont chaque page
serait une case mémoire, le numéro de la page étant son adresse.
Son utilisation première reste, dans notre cas, la variable. En effet, cette dernière n'est autre qu'une case mémoire dans
laquelle il est possible de stocker du texte (STRING), des entiers (INT), etc. En fait, une variable n'est qu'un nom que le
compilateur comprendra comme une adresse numérique qu'il transmettra au microprocesseur. Comme nous sentons que ce n'est pas
très clair dans votre esprit, voici un petit exemple :
/* Adresse et contenu d'une variable */
DEF var
PROC main()
var:=3
WriteF('l''adresse de var est : \d\n',{var})
WriteF('var contient : \d\n',var)
ENDPROC
|
var est une variable INT (entier) dans laquelle nous stockons 3. Son adresse pour le microprocesseur est notée en langage E: {var}.
Les pointeurs
Les pointeurs sont des variables dans lesquelles, au lieu de stocker des informations, nous stockons des adresses numériques
compréhensibles par le microprocesseur. Acoissacerdonc ? Ceux-ci nous seront très utiles pour l'utilisation des fonctions du
système qui ne raisonnent que sur des adresses, comme ReadArgs() que nous avons rencontré le mois dernier.
Petit exemple :
/* Utilisation d'un pointeur */
DEF chaine[30]:STRING
DEF p:PTR TO INT
PROC main()
chaine:='Ceci est une chaîne'
p:={chaine}
WriteF('l''adresse de chaine
est: \d\n',{chaine})
WriteF('p pointe sur l''adresse : \d\n',p)
WriteF('le contenu de la case pointée
par p est : \d\n',^p)
ENDPROC
|
"chaine" est une variable de type STRING (chaîne de caractères) à laquelle nous affectons la valeur 'Ceci est une chaîne'.
"p" est un pointeur auquel nous affectons l'adresse de "chaine". Nous avons donc un pointeur p qui pointe sur une chaîne de
caractères. La valeur de p est l'adresse à laquelle se trouve la chaîne de caractères. Pour accéder au contenu de l'adresse
pointée par un pointeur, il faut utiliser le symbole ^ suivi du nom du pointeur. Ainsi ^p représente le contenu de la chaîne de
caractères "chaine" ('Ceci est une chaîne').
Pointeurs et Objects
Comme nous l'avons vu dans le premier article, nous pouvons rassembler plusieurs
variables en une seule par l'intermédiaire des Objets. Reprenons l'exemple de notre bibliothèque de CD :
OBJECT cd
nom[50]:STRING /* nom du cd */
durée:INT /* durée en min */
plages:INT /* nb de plages */
ENDOBJECT
|
Nous avons créé un type CD, et à chaque fois que nous affectons ce type à une variable :
Nous créons en fait un pointeur sur une zone mémoire qui contient toutes les variables définies dans l'objet. Pour accéder à
celles-ci, nous utilisons un adressage dit relatif de la forme : nom du pointeur.nom de la variable. Exemple : metallica.nom.
Que cache cette syntaxe ? Le compilateur dit au processeur de manipuler la variable "nom", d'un objet CD, à partir du pointeur
metallica. Vous voulez un exemple d'utilisation ? Très bien. Imaginons que nous possédons un tableau (mescd[]) constitué de la
liste des pointeurs sur les CD de notre audiothèque. Nous créons un pointeur (pcd) qui pourra pointer sur un objet de type CD :
Pour connaître le nom du troisième CD de la liste, il nous suffit d'écrire :
pcd:=mescd[3]
WriteF('nom du cd:\s\n',pcd.nom)
|
Nous affectons à pcd le 3e élément du tableau de pointeur sur les CD (pcd[3]), et nous écrivons à l'écran le nom du cd (pcd.nom).
Le programme ReadArgs
Étant donné que nous avons décrit en détail les pointeurs, nous ne nous attarderons pas sur la partie du programme qui y fait
référence. Tout notre programme se trouve dans la procédure main(), mais rien ne vous empêche d'en faire une procédure générique
que vous pourrez inclure dans vos programmes personnels.
Après les définitions de i et de rdargs qui nous permettrons de gérer les boucles et de lancer la fonction ReadArgs(), nous
définissons result qui est un pointeur sur un mot long et args qui est un tableau de 32 mots longs (pointeurs). La première
boucle sert à initialiser (mise à zéro) les 32 arguments. La partie principale du programme se trouve à l'intérieur d'un
test qui vérifie que la fonction ReadArgs() renvoie bien une structure rdargs. Il convient maintenant de nous attarder sur
cette fonction de la bibliothèque DOS.
Le langage E peut très bien gérer les arguments, alors pourquoi utiliser la fonction de la dos.library ? Cette fonction est
bien plus puissante que la gestion des arguments par le E. Elle permet de définir les arguments souhaités (texte, nombres...)
ainsi que leur modificateurs (traduction française de "modifiers") qui peuvent être /S (switch), /K (keyword), /N (number),
/T (toggle), /A (Required), /F (Rest of line), /M (multiple strings).
De plus, ReadArgs() renvoie un pointeur pour chaque information alors que la variable arg du E ne retourne qu'une chaîne de
caractères qu'il faut ensuite traiter. Nous vous conseillons de vous référer aux Autodocs pour de plus amples informations sur
cette fonction (et les autres !).
Revenons au programme. Nous appelons la fonction ReadArgs() avec comme paramètres une chaîne de formatage et le tableau de mots
longs pour récupérer le résultat. Si vous avez compris les modificateurs, vous vous apercevez que nous désirons récupérer des
arguments dont les quatre premiers sont des nombres et les suivants des chaînes de caractères. A noter que seul le premier
argument est obligatoire (/A). Si l'utilisateur entre au clavier un mauvais argument (par exemple, un nombre à la place d'une
chaîne de caractères), la fonction ReadArgs() renvoie un code d'erreur et notre programme affiche alors la ligne d'usage.
Le reste du programme se charge uniquement d'afficher les arguments avec tout d'abord dans la première boucle les quatre nombres
(de 0 à 3) dont nous allons rechercher la valeur à l'aide du signe ^ vu plus haut. C'est un peu plus compliqué pour les chaînes
de caractères suivantes, étant donné que nous ne savons pas combien il y en a. La fonction ReadArgs() nous renvoie l'adresse
d'un tableau de pointeurs sur les différentes chaînes de caractères. Il faut, dans ce cas, tester si l'on arrive en fin de tableau
(pointeur nul) avec une instruction WHILE. Une fois le programme terminé, il convient de rendre la mémoire allouée par la
fonction ReadArgs() pour sa structure (rdargs) et cela à l'aide la fonction FreeArgs(rdargs).
Voilà, nous pensons avoir à peu près fait le tour de la question. C'est promis, le mois prochain, on essaye de faire un peu plus
concret. Il serait intéressant que vous écriviez au journal pour nous faire part de vos impressions et pour nous aiguiller quant
à nos articles futurs. Atchao, bonsoir.
/* Exemple de lecture d'arguments */
PROC main()
DEF rdargs,i,result:PTR TO LONG
DEF args[32]:ARRAY OF LONG /* 32 arguments au maximum */
FOR i:= 0 TO 31
/* initialisation du tableau de pointeur des arguments */
args[i]:=0
ENDFOR
IF rdargs:=ReadArgs('/N/A,/N,/N,/N,/M',args,NIL)
FOR i:=0 TO 3
result:=args[i]
/* chaque entrée du tableau pointe sur un nombre */
WriteF('argument n°:\d =\d\n',1+i,^result)
/* ^result va chercher la valeur pointée par le tableau */
ENDFOR
i:=0
result:=args[4]
/* /M renvoie un tableau de pointeur sur des chaines */
WHILE result[i]<>NIL
WriteF('argument n°:\d = ',5+i,result[i])
i++
ENDWHILE
FreeArgs(rdargs)
ELSE
WriteF('Usage: Number/N/A Number/N
Number/N Number/N text ...')
ENDIF
ENDPROC
|
|