%ADDR
Adresse mémoire d'une zone
Renvoie un pointeur sur l'adresse en mémoire d'une zone, d'une structure de données ou d'un élément de tableau.
Syntaxe
%ADDR(variable)
%ADDR(variable : *DATA)
variable- La zone, la structure de données ou l'élément de tableau dont on veut l'adresse.
*DATA- Pour une zone de longueur variable (
varchar) seulement : l'adresse du texte, après les deux octets de longueur. - Résultat
- Une valeur de type pointeur (
pointer).
À quoi ça sert
Un pointeur permet de regarder la même mémoire avec deux déclarations différentes (zone based), de passer l'adresse d'une zone à une API, ou de parcourir une zone tampon.
Dans l'exemple, une zone based n'a pas de mémoire propre : elle se superpose à l'adresse contenue dans le pointeur. Lire ou écrire cette zone revient à lire ou écrire la zone d'origine.
Exemple 1 : Superposer une zone sur une autre
**free
// %ADDR : adresse d'une zone, d'une structure ou d'un element de tableau.
ctl-opt dftactgrp(*no) actgrp(*new);
dcl-s ville char(12) inz('Montpellier');
dcl-s montants packed(7:2) dim(3);
dcl-s p pointer;
dcl-s q pointer;
// Zone "basee" : elle n'a pas de memoire propre, elle s'applique a l'adresse du pointeur.
dcl-s vue char(12) based(p);
dcl-s unMontant packed(7:2) based(q);
montants(1) = 100.10;
montants(2) = 200.20;
montants(3) = 300.30;
p = %addr(ville);
snd-msg 'Vue sur ville : [' + vue + ']';
vue = 'Lyon';
snd-msg 'Ville modifiee : [' + ville + ']';
q = %addr(montants(2));
snd-msg 'Element 2 : ' + %char(unMontant);
unMontant = 999.99;
snd-msg 'Tableau : ' + %char(montants(1)) + ' / ' + %char(montants(2))
+ ' / ' + %char(montants(3));
// Les adresses de deux zones differentes ne sont jamais egales.
snd-msg 'Meme adresse ? ' + %char(%addr(ville) = %addr(montants));
snd-msg 'Adresse egale : ' + %char(p = %addr(ville));
*inlr = *on;
Résultat réel, compilé et exécuté sur IBM i 7.5 :
Vue sur ville : [Montpellier ]
Ville modifiee : [Lyon ]
Element 2 : 200.20
Tableau : 100.10 / 999.99 / 300.30
Meme adresse ? 0
Adresse egale : 1
La zone vue est posée sur ville : écrire 'Lyon' dans vue change ville. Avec l'adresse de montants(2), on atteint le deuxième élément du tableau et on le modifie (999,99). Deux zones différentes n'ont jamais la même adresse.
Exemple 2 : Adresse d'une zone variable
**free
// %ADDR sur une zone variable : le debut de la zone n'est pas le debut du texte.
ctl-opt dftactgrp(*no) actgrp(*new);
dcl-s nom varchar(20) inz('Dupont');
dcl-s pZone pointer;
dcl-s pTexte pointer;
dcl-s longueur int(5) based(pZone);
dcl-s texte char(6) based(pTexte);
pZone = %addr(nom);
pTexte = %addr(nom : *data);
snd-msg 'Ecart entre les deux adresses : ' + %char(pTexte - pZone) + ' octets';
snd-msg 'Deux premiers octets (longueur) : ' + %char(longueur);
snd-msg 'Texte a l''adresse *DATA : [' + texte + ']';
*inlr = *on;
Résultat réel, compilé et exécuté sur IBM i 7.5 :
Ecart entre les deux adresses : 2 octets
Deux premiers octets (longueur) : 6
Texte a l'adresse *DATA : [Dupont]
Une zone varchar commence par 2 octets de longueur. %addr(nom) pointe sur cette longueur (valeur 6 pour « Dupont »), %addr(nom : *data) pointe 2 octets plus loin, sur le texte.
Le piège
Pour un varchar, l'adresse n'est pas celle du texte. %addr(nom) pointe sur les 2 octets de longueur : lu comme du texte, on obtient des caractères illisibles. Il faut %ADDR(nom : *DATA), qui pointe 2 octets plus loin (exemple 2).
*DATA n'est accepté que pour une zone de longueur variable : sur une zone fixe, le compilateur refuse avec le message RNF0229.