Pointeurs et accès mémoire
Pointeurs
L'utilisation des pointeurs est possible en plaçant une * devant le nom de la variable.
Un pointeur est une variable qui stocke une adresse mémoire et qui est généralement associé à une structure.Exemple:
*MonEcran.Ecran = OpenScreen(0,320,200,8,0)Il existe seulement trois méthodes valides pour fixer la valeur d'un pointeur:
mouseX = *MonEcran\SourisX ; La structure Ecran devant contenir un champ SourisX
- Obtenir le résultat par une fonction (voir l'exemple ci-dessous)
- Copier la valeur d'un autre pointeur
- Trouver l'adresse d'une variable, procédure ou label (voir ci-dessous)
A Noter : A l’inverse du C/C++, en PureBasic l'* fait partie intégrante du nom de la variable. Aussi ptr et *ptr sont deux variables bien distinctes.
ptr est une variable (régulière) contenant une valeur, *ptr est une autre variable de type pointeur contenant une adresse.
Pointeurs et taille mémoire
Comme un pointeur reçoit uniquement une adresse mémoire comme valeur, sa taille en mémoire sera celle qui permettra de représenter une adresse du processeur :
- Sur un processeur 32 bits, les adresses sont représentées sur 32 bits, par conséquent un pointeur prendra 32 bits en mémoire (soit 4 octets comme une variable de type ‘long’).
- Sur les processeurs 64 bits, les adresses sont représentées sur 64 bits, ce qui implique qu'un pointeur prendra 64 bits en mémoire (soit 8 octets comme une variable de type ‘quad’).
C’est pour cette raison qu’un pointeur est une variable dite de type pointeur car son encombrement en mémoire sera lié à la capacité d’adressage mémoire du processeur.
Il en découle qu’affecter un type à un pointeur (*Pointeur.l, *Pointeur.b…) n’a aucun sens puisque l’encombrement mémoire d’un pointeur est imposé par celui d’une adresse et non par celui d’un type.
A Noter :
- A chaque fois qu’une adresse mémoire doit être stockée dans une variable, il faudrait le faire par l’intermédiaire d’un pointeur. Ceci garanti que l’adresse sera correctement représentée lors de la compilation du code que ce soit par un processeur 32 bits comme par un processeur 64 bits par exemple.
- PureBasic ne permet pas encore de créer des exécutables 64 bits. Tant que les exécutables PureBasic seront compilés en 32 bits, le système ne leur offrira seulement des adressages long de 32 bits.
Pointeurs et structures
Attacher une structure à un pointeur (par exemple *MonPoint.Point) permet d’accéder au contenu mémoire de chaque membre de la structure avec le caractère \ .
Exemple:
Point1.PointLes pointeurs permettent donc de se déplacer, de lire et d’écrire facilement en mémoire. De plus ils permettent aux programmeurs d’accéder à de grandes quantités de données sans coût supplémentaire suite à une duplication de ces données. Copier un pointeur est beaucoup plus rapide.
Point2.Point
*PointCourant.Point = @Point1 ; Déclare le pointeur, l'associe a une structure et l'initialise avec l'adresse de Point1
*PointCourant\x = 10 ; Assigne la valeur 10 à Point1\x
*PointCourant.Point = @Point2 ; Récupère l'adresse de Point2
*PointCourant\x = 20 ; Assigne la valeur 20 à Point2\x
Debug Point1\x
Debug Point2\x
Pointeurs et chaînes de caractères
Toutes les variables ont une taille fixe en mémoire (2 octets pour un Word, 4 octets pour un Long, etc…) hormis les chaînes de caractères dont la longueur peut changer, ce qui fait qu’elles sont gérées différemment.
Ainsi, les champs d’une structure faisant référence à une chaîne de caractères stockent l’adresse mémoire où réside la chaîne de caractères et non la chaîne elle-même: ce sont des pointeurs vers des chaînes de caractères.
Exemple:
Texte$ = "Bonjour"Arithmétiques des pointeurs
*Texte = @Texte$ ;*Texte a pour valeur l’adresse où réside la chaîne de caractères en mémoire
*Pointeur.String = @*Texte ; *Pointeur pointe sur *Texte
Debug *Pointeur\s ; Lit la chaîne de caractères qui réside à l’adresse écrite en *Pointeur (c-a-d @Texte$)
Il est possible d'effectuer des opérations arithmétiques sur les pointeurs en s'aidant de la commande SizeOf().
Exemple:
Dim Tableau.Point(1) ; tableau de points
*Pointeur.Point = @Tableau() ; Récupère l'adresse du tableau
*Pointeur\x = 10 ; Modifie l'élément 0 du tableau
*Pointeur\y = 15
*Pointeur + SizeOf(POINT) ; Passe à l'élément suivant du tableau
*Pointeur\x = 7 ; Modifie l'élément 1 du tableau
*Pointeur\y = 9
;Affiche le résultat
For i = 0 To 1
Debug Tableau(i)\x
Debug Tableau(i)\y
Next i
Adresses des variables
Pour trouver l'adresse d'une variable dans votre code, utilisez le symbole @. La raison la plus fréquente d'utiliser ce système est le transfert d'une variable de type structure à une procédure. Il faut passer un pointeur à la procédure car il est impossible de passer directement la structure comme argument.Exemple:
Structure astruct
a.w
b.l
c.w
EndStructure
Procedure SetB(*monpointeur.astruct)
*monpointeur\b = 69
EndProcedure
Define.astruct mavariable
mavariable\b = 0
SetB( @mavariable )
Debug mavariable\b
Adresses des procédures
En principe seuls les programmeurs avancés ont à connaître l'adresse d'une procédure. La raison la plus fréquente est de devoir négocier des échanges de bas niveau avec le système d'exploitation. Certains systèmes autorisent la mise en place de callbacks ou points d'ancrage (hooks) permettant au système d'exploitation de dialoguer avec le programme en étendant ainsi les capacités du système d'exploitation. L'adresse d'une procédure est accessible d'une manière similaire à une variable.Exemple:
Procedure WindowCB(WindowID.l, Message.l, wParam.l, lParam.l)
; C'est ici que le traitement de votre callback sera effectué
EndProcedure
; Un callback spécifique pour Windows permet de traiter les évènements sur les fenêtres
SetWindowCallback( @WindowCB() )
Adresses des labels
Il peut également être utile de connaître l'adresse d'un label dans votre programme. Cela peut être le cas pour accéder au code ou aux données placées à cet endroit ou toute autre bonne raison qui peut vous venir à l'esprit. Pour trouver l'adresse d'un label dans votre programme, placez un '?' devant le nom du label.Exemple:
Debug "Taille du fichier de données = " + Str(?endofmydata - ?mydata)
DataSection
mydata:
IncludeBinary "somefile.bin"
endofmydata: