RPG IV permet de manipuler des pointeurs 1/ pointeur d'adresse, pointe sur un espace mémoire(variable ou *USRSPC) Les pointeurs d'adresse peuvent être utilisés avec les APIs de gestion dynamique de mémoire (le "tas", heap en anglais). 2/ pointeur de procédure, pointe sur une procédure liée dans le même pgm. Définition d'un pointeur : variable de 16 octets (sur AS) contennant une adresse virtuelle. (la notion de tableau de pointeurs est admise) Déclaration en RPG: Spécif D: !-- type de variable "*" = pointeur. Pointeur d'adresse. v DSPACE S * [DIM(xxx) = tableau de pointeurs] Pointeur de procédure. DPROC S * PROCPTR |
Un pointeur contient par défaut la valeur *NULL, il ne pointe sur rien. il peut se voir assigner une valeur de deux manières: Copie du contenu d'un pointeur dans un autre C eval ptr1 = ptr2 Résolution d'une adresse Adresse d'une structure (variable, DS, tableau, etc..) pour un pointeur d'adresse. C eval ptr1 = %ADDR(variable) Adresse d'une procédure liée(en respectant la notation minuscule/MAJUSCULE) pour un pointeur de procédure. C eval pptr = %PADDR('nom-procédure') La résolution peut être faite lors de l'initialisation du pgm par : DSPACE S * INZ(%ADDR(variable)) DPROC S * PROCPTR INZ(%PADDR('nom-proc')) |
Et enfin, des APIs systèmes renvoient maintenant des pointeurs : QUSPTRUS, retourne le pointeur de début d'un User Space (manipulation plus rapide) CEEGTST, API liable, alloue dynamiquement de la mémoire et retourne l'adresse de début sous forme de pointeur. (voir plus loin dans ce cours) Manipulation: Les pointeurs s'utilisent de la manière suivante: 1/ on va définir une structure (en général DS), basée sur un pointeur. Dptr S * Ddata DS based(ptr) D zone1 5 D zone2 10 D zone3 7 2 |
Il s'agit d'une structure "théorique", qui n'a pas d'existence propre, et qui viendra découper la zone mémoire référencée par le pointeur, quand ce dernier aura une valeur valide. l'instruction Z-ADD 0 ZONE3 provoque une erreur MCHxxxx, si ptr n'a pas été renseigné. Quelques exemples: Dstructur DS D zona 5 D zonb 10 D zonc 12 Dptr S * Dsolo S 10 based(ptr) C eval ptr = %ADDR(zonb) C* test vrai : C if solo = zonb C* également vrai : C if %addr(solo) = %addr(zonb) |
Dtbl S 5 DIM(30) Dtbptr S * DIM(30) C eval tbptr(1) = %ADDR(tbl) * tbptr(1) contient l'adresse de tbl, élément n°1 (début de tableau) C eval tbptr = %ADDR(tbl) * tous les éléments de tbptr contiennent l'adresse de tbl, élément 1 C eval tbptr = %ADDR(tbl(*)) * chaque élément de tbptr contient l'adresse de l'élément de même rang dans tbl [tbptr(1) = adresse de tbl(1), tbptr(2) = adresse de tbl(2), etc...] Utilisation : V3R10 Pour ce déplacer dans une structure il faut redéfinir la variable dans laquelle on veut se déplacer, sous forme de tableau de x fois 1 c. V3R70 Ceci a été corrigé en V3R7, qui accepte prt = ptr + x . |
Dfiller DS D espace 32767 Dptr S * Ddata DS based(ptr) D zone1 5 D zone2 10 ################# D zone3 5S 2 # # * initialisation au début de la structure # EXEMPLE : # --> C eval ptr = %addr(espace) # # C eval x = 1 # (suivez --> ) # * décalage d'une longueur ################# C eval ptr = ptr + %size(data) Soit espace (adresse=12601) : 1 2 3 4 4 12600....+....0....+....0....+....0....+....0....+....9 + 50 CODE1code n° un12345CODE2code n° 2 67890CODE3code +100 n° 3 54321CODE5code n° 5 98765CODE6code n° 6 43210 +150 etc ... etc ... ptr = *NULL ! x = ! data = ' ' |
Dfiller DS D espace 32767 Dptr S * Ddata DS based(ptr) D zone1 5 D zone2 10 ################# D zone3 5S 2 # # * initialisation au début de la structure # Modifier ptr # --> C eval ptr = %addr(espace) # = # C eval x = 1 # modifier DATA # * décalage d'une longueur ################# C eval ptr = ptr+ %size(data) Soit espace (adresse=12601) : 1 2 3 4 4 12600....+....0....+....0....+....0....+....0....+....9 + 50 CODE1code n° un12345 ODE2code n° 2 67890CODE3code +100 n° 3 54321CODE5code n° 5 98765CODE6code n° 6 43210 +150 etc ... etc ... ptr = 12601 ! x = ! data = 'CODE1code n° un12345' |
Dfiller DS D espace 32767 Dptr S * Ddata DS based(ptr) D zone1 5 D zone2 10 ################# D zone3 5S 2 # # * initialisation au début de la structure # x = 1 # ### C eval ptr = %addr(espace) # # --> C eval x = 1 # # * décalage d'une longueur ################# C eval ptr = ptr+ %size(data) 1 2 3 4 4 12600....+....0....+....0....+....0....+....0....+....9 + 50 CODE1code n° un12345 ODE2code n° 2 67890CODE3code +100 n° 3 54321CODE5code n° 5 98765CODE6code n° 6 43210 +150 etc ... etc ... ptr = 12601 ! x = 1 ! data = 'CODE1code n° un12345' |
Dfiller DS D espace 32767 Dptr S * Ddata DS based(ptr) D zone1 5 D zone2 10 ################# D zone3 5S 2 # # * initialisation au début de la structure # %size(data) # ### C eval ptr = %addr(espace) # = 20, donc # C eval x = 1 # ptr = 12621 # * décalage d'une longueur ################# --> C eval ptr = ptr+ %size(data) 1 2 3 4 4 12600....+....0....+....0....+....0....+....0....+....9 + 50 CODE1code n° un1234 CODE2code n° 2 67890 ODE3code +100 n° 3 54321CODE5code n° 5 98765CODE6code n° 6 43210 +150 etc ... etc ... ptr = 12621 ! x = 21 ! data = 'CODE2code n° 2 67890' |
Dfiller DS D espace 32767 Dptr S * Ddata DS based(ptr) D zone1 5 D zone2 10 ################# D zone3 5S 2 # si cet # * initialisation au début de la structure # ordre est # ### C eval ptr = %addr(espace) # dans une # C eval x = 1 # boucle, on # C DOU ... # va "pointer" # --> C eval ptr=ptr+%size(data) # tous les # # éléments de # 1 2 3 4 # "espace" # 12600....+....0....+....0....+....0....+....0....+....9 ################# + 50 CODE1code n° un12345CODE2code n° 2 6789 CODE3code +100 n° 3 54321 ODE5code n° 5 98765CODE6code n° 6 43210 +150 etc ... etc ... ptr = 12641 ! x = 41 ! data = 'CODE3code n° 3 54321' |
C'est la technique qu'il faudra utiliser avec les User Space. Avec l'APi d'allocation dynamique de mémoire il faudra utiliser les listes chainées: Dtas_id S 9B 0 INZ(0) Ddta_size S 9B 0 INZ(%size(data)) * l'API CEEGTST doit faire référence à un tas créé au préalable * (par API CEECRHP, qui renvoie un identifiant binaire) ou utiliser * le tas par défaut que chaque groupe d'activation possède. * * Il faut alors initialiser l'indentifiant à zéro binaire. Dwptr S * Dptr S * Ddata DS based(ptr) D preced * D zone1 5 D zone2 10 D zone3 5S 2 D suivant * * intialisation du premier poste |
C callb 'CEEGTST' C parm tas_id C parm dta_size C parm ptr C eval preced = *NULL (pas de précédent) * C DOU ( test logique) C* traitement de ce poste C* et allocation du suivant C if (même test logique) C callb 'CEEGTST' C parm tas_id C parm dta_size C parm suivant (addr du suivant) C eval wptr = ptr C eval ptr = suivant C eval preced = wptr (addr du précédent) C* ou fin de liste C else C eval suivant = *NULL (pas de suivant) C endif |