Utilisez des pointeurs pour rendre vos programmes CRBasic plus efficaces

par Gary Roberts | Mis à jour le : 03/23/2017 | Commentaires : 2

Les thèmes principaux du Blog


Recherche sur le Blog


Langages du blog

English
Français (French)


Abonnez-vous au Blog

Recevez un courriel lorsqu'un nouvel article est posté. Choisissez les sujets qui vous intéressent le plus.


Entrez votre adresse courriel :



Suggérer un article

Y a-t-il un sujet que vous souhaiteriez nous voir aborder ? Laissez-nous un message.

Leave this field empty

Les pointeurs (Pointers en anglais) sont un excellent outil pour les programmes CRBasic. Si vous les utilisez avec soin, les pointeurs peuvent réduire la quantité de code de programme que vous devez écrire, ce qui augmente l'efficacité de votre programme et vous permet d'utiliser moins de mémoire. (Votre programme peut s'exécuter plus rapidement car il n'a pas à dupliquer les données en mémoire).

Pour apprendre à utiliser les pointeurs, il serait utile de parler d'abord des variables et de la façon dont elles sont stockées. Les variables sont stockées dans des cellules de mémoire à l'intérieur de la mémoire de la centrale de mesure. La mémoire de la centrale de mesure est composée de cellules de mémoire consécutives, d'un octet de long, chacune avec une adresse unique. Pour mieux comprendre comment une centrale d'acquisition utilise sa mémoire, je vais utiliser l'analogie ci-dessous, ce qui devrait vous aider lorsque nous commençons à parler de pointeurs.

Comprendre la mémoire de la centrale de mesure

Imaginez que la mémoire de la centrale de mesure est un grand entrepôt qui peut stocker beaucoup de choses à l'intérieur. Dans notre exemple, nous allons remplir notre entrepôt avec des seaux de différentes tailles et types. (Selon nos besoins, nous pouvons remplir l'entrepôt entier ou seulement une partie de celui-ci.) Tous les seaux que nous utilisons tiennent des choses d'un type ou d'un autre. Des seaux plus grands sont utilisés pour contenir des choses plus grandes, et des seaux plus petits sont utilisés pour les petites choses. Le nombre et la taille des seaux utilisés, ainsi que la quantité d'espace utilisé dans l'entrepôt, dépendent de vous en tant que programmeur et des besoins du projet sur lequel vous travaillez.

Lorsque nous commençons à écrire notre programme CRBasic, nous déclarons les variables. Dans notre scénario d'entrepôt, lorsque nous déclarons une variable, nous créons un seau (en utilisant des cellules de la mémoire) dans l'entrepôt de la centrale d'acquisition pour contenir l'information (variable) avec laquelle nous voulons travailler. Ce seau ne peut contenir que certains types de variables. Par exemple, un petit seau contient une variable flottante et occupe environ 4 octets de l'espace libre d'entrepôt (mémoire) de la centrale de mesure. Un autre petit seau contient une variable booléenne, et il prend également 4 octets d'espace au sol dans l'entrepôt. Nous ajoutons ensuite un grand seau qui contient une chaîne de variable, qui prend 24 octets d'espace d'entrepôt.

Avec un entrepôt rempli de seaux, comment pouvons-nous savoir quel seau détient quel morceau d'information que nous voulons ? Heureusement, nous avons la capacité de donner des noms significatifs à nos seaux qui aident à décrire le morceau d'information qu'ils détiennent. Par exemple, nous pouvons donner le nom de température (ou temperature en anglais) à un seau qui contient une variable flottante en déclarant notre flotteur variable comme température. Alors que nous continuons à ajouter et à déclarer des variables, l'entrepôt (la mémoire) de la centrale de mesure commence à se remplir.

Si notre entrepôt est plein, comment pouvons-nous facilement trouver le seau que nous avons besoin ? Heureusement, le processeur de la centrale de mesure est un gestionnaire d'entrepôt fantastique. Il sait où se trouve chaque seau. Chaque seau a une adresse spécifique et unique avec une allée, une section et une étagère dans l'entrepôt de la centrale de mesure. (Deux seaux ne partage pas la même adresse.) Le gestionnaire d'entrepôt peut utiliser l'adresse unique pour trouver rapidement le seau dans l'entrepôt. Lorsque nous arrivons à l'entrepôt et que nous voulons que le godet porte la variable flottante que nous appellerons température - temperature, la centrale d'acquisition de mesure décode efficacement l'adresse et obtient le godet droit (cellule de mémoire de la centrale de mesure) que nous recherchons et l'information (variable) qu'il contient. Nous pouvons alors lire ou modifier ce qui est à l'intérieur du seau de température - temperature (comme, température - temperature = 32.14).

La base des pointeurs

Maintenant, voici où les pointeurs entrent en jeu. Les pointeurs (pointers) sont un moyen pour nous d'aider notre gestionnaire d'entrepôt (le processeur de la centrale de mesure) à être encore plus efficace dans son travail et être un meilleur gestionnaire de l'espace d'entrepôt limité (mémoire).

Un pointeur (pointer) est une variable dont la valeur est l'adresse d'une autre variable. Tout comme n'importe quelle variable ou constante, vous devez déclarer un pointeur avant de pouvoir y travailler. Lorsque vous déclarez un pointeur dans CRBasic, il doit être déclaré comme un type Long :

Public my_pointer As Long

Cette ligne de code est appelée la déclaration du pointeur (pointer) ou la variable de pointeur. La variable pointeur stocke l'adresse de l'autre variable à laquelle nous voulons pointer.

Pour utiliser ou initialiser le nouveau pointeur (pointer), nous devons alors indiquer à CRBasic de le pointer vers une mémoire spécifique liée à la variable de température ou temperature. Pour ce faire, nous pouvons utiliser la syntaxe suivante :

my_pointer = @temperature  
L'adresse mémoire (entrepôt) de la température - temperature est maintenant mémorisée dans la variable pointeur my_pointer. Le symbole @ est connu sous le nom d'opérateur d'adresse. C'est un opérateur unaire qui renvoie l'adresse mémoire de son opérande. En utilisant l'exemple ci-dessus, my_pointer est maintenant égal à l'adresse de la température - temperature.

Cela nous permet maintenant de faire plusieurs choses dans notre programme CRBasic. Par exemple :

Public my_pointer As Long
Public mike As Long, tom As Long, melissa As Long 
my_pointer = @mike
mike = 42
tom = mike
melissa = my_pointer

Dans ce court programme CRBasic, les conditions suivantes sont remplies :

  • mike est maintenant égal à 42.
  • Parce que tom est égal à mike, tom égale égale à 42.
  • melissa est maintenant égal à l'adresse mémoire de mike.
  • melissa n'est pas égal à 42 mais à un certain numéro d'adresse mémoire assigné à la variable mike par la centrale de mesure.
  • melissa est maintenant aussi un pointeur comme la variable my_pointer parce que melissa a les mêmes informations que my_pointer.

Si nous voulons que la variable melissa contienne la même valeur que mike (et non l'adresse mémoire de mike), nous devons utiliser la déréférence du pointeur ou l'opérateur d'indirection ! Comme illustré ici :

Public my_pointer As Long
Public mike As Long, tom As Long, melissa As Long 
my_pointer = @mike
mike = 42
tom = mike
melissa = !my_pointer

Maintenant melissa est égal à 42-tout comme mike et tom.

Eh bien voilà qui est parfait, mais ne serait-il pas simplement plus facile de mettre melissa égal à mike ? La plupart du temps, oui. Il y a des moments où un pointeur est plus pratique, mais c'est un sujet plus complexe.

Utilisation des pointeurs (Pointers)

Maintenant, utilisons les pointeurs.

Dans l'article du blog ''6 étapes pour analyser facilement les données d'une source fiable”, J'ai partagé avec vous comment analyser XML à partir d'autres sources en utilisant une centrale de mesure CRBasic. Maintenant, je vais vous montrer comment nous pouvons utiliser des pointeurs pour améliorer et raccourcir le programme, afin d'économiser précieusement la mémoire de la centrale de mesure.

Dans ce premier article de blog, le programme que j'ai partagé avec vous a cherché et lu une variable du fichier XML. Pour obtenir plus d'informations à partir du XML renvoyé, nous allons devoir ajouter plus de déclarations IF afin d'obtenir les informations dont nous avons besoin (comme l'humidité) :

If xml_response_code = XML_END_OF_ELEMENT AND xml_element_name = "relative_humidity" Then noaa_releative_humidity = xml_value
EndIf

Pour obtenir toutes les données du fichier XML, nous devrions ajouter trente-quatre déclarations IF supplémentaires pour obtenir de tout analyser. Maintenant, à l'aide de pointeurs (pointer), nous pouvons obtenir le même travail avec une seule instruction IF !

If xml_response_code = XML_END_OF_ELEMENT Then 
	pointer = 0 
	pointer = @(xml_element_name) 
	If(pointer > 0) Then !pointer = xml_value
EndIf

Ce que nous avons fait est de déclarer les variables que nous voulons pour stocker des informations, en utilisant les mêmes noms exacts que les éléments dans le fichier XML. Ce faisant, nous utilisons des pointeurs dans notre centrale de mesure et rendons notre programmation plus compacte et plus précise.

Avec des pointeurs (pointers), notre programme télécharge le XML comme avant et commence à l'analyser à l'aide de l'instruction XMLParse(). Lorsqu'il arrive à la fin d'un nom d'élément, nous commençons l'analyse dans notre instruction IF. La première ligne de cette instruction IF place le pointeur sur l'adresse mémoire 0. C'est juste une bonne pratique de programmation, car la centrale de mesure ne renverra jamais une référence à une variable à l'adresse 0. Cela nous aide (et la centrale d'acquisition de mesure) à savoir si la déréférence dans la ligne suivante de code a fonctionné ou a échoué.

La ligne suivante définit le pointeur sur l'opérateur d'adresse de l'opérateur (@) pour la variable du même nom que celle stockée dans la variable xml_element_name. Les parenthèses autour du nom de la variable xml_element_name indiquent à la centrale d'acquisition de mesure de ne pas regarder l'adresse de xml_element_name, mais d'examiner ce qui est stocké dans xml_element_name. Par exemple, lorsque xml_element_name = "relative_humidity" le pointeur de variable pointe vers l'adresse mémoire de la variable nommée relative_humidity et non vers xml_element_name. C'est pourquoi nos noms de variables doivent être nommés identiques aux éléments du fichier XML que nous analysons.

The last line in the statement says that if the pointer is not pointing to memory address zero, pour the information in xml_value into the variable at the address that pointer is pointing at. Using our previous example, the value stored in xml_value would be dumped into the variable relative_humidity.

La dernière ligne dans l'instruction indique que si le pointeur ne pointe pas vers l'adresse de mémoire zéro, versez les informations dans xml_value dans la variable à l'adresse où le pointeur pointe. En utilisant notre exemple précédent, la valeur stockée dans xml_value serait déchargée dans la variable relative_humidity.

De plus amples informations

J'ai inclus un exemple fonctionnel d'un programme utilisant XMLParse() et des pointeurs (pointers). Il suffit de télécharger ce programme CRBasic dans votre centrale d'acquisition de données (s'assurer que votre centrale de mesure a une connexion Internet active), de l'exécuter et de regarder la mise à jour du programme à l'aide de pointeurs.

J'espère que cet article vous a été utile. Si vous avez des questions, veuillez les poster ci-dessous.


Partagez cet article


A propos de l'auteur

gary roberts Gary Roberts est le responsable produit communications et des produits logiciels chez Campbell Scientific, Inc. Il passe ses journées à rechercher de nouvelles technologies, à trouver des solutions aux problèmes pour les produits phares, à faire du support de second niveau pour les équipements Campbell. La formation et l'expérience de Gary sont en technologie de l'information et informatique. Lorsqu'il n'est pas au travail, il jouit du grand air avec ses Scouts, lutte contre le feu / EMS, pratique la radio en tant qu'amateur, ou la programmation des ordinateurs.

Voir tous les articles de cet auteur.


Commentaires

kelly | 02/16/2018 at 04:56 AM

This is a few lines from the help file.

"

Pointers can be accessed within expressions:

!(Pointer + X)

will access the value at Pointer + X.

"

so, using this call:

UnpackArray(PkAryVal, @UnPack(),12)

Why does this work:

Sub UnpackArray(Val As Long, AryPtr As Long, Elements As Long)
 Dim Ref As Long
 Dim x As Long
 For x = 0 To Elements - 1
 Ref = AryPtr + x
 !Ref = (Val >> x AND 1)
 Next x
EndSub

but not this:

Sub UnpackArray(Val As Long, AryPtr As Long, Elements As Long)
Dim x As Long
For x = 0 To Elements - 1
!(AryPtr + x) = (Val >> x AND 1)
Next x
EndSub

Testing on CR6 os 6.08

Thanks for any light that can be shed on this issue

crs | 04/07/2018 at 03:51 PM

I would love to see more blog posts / tutorials on using pointers in CRBasic. 

I am trying to write a function that can accept any type of variable (or array) and perform some operation on it (e.g., using TypeOf() and SprintF()), but not having any luck recognizing the original variable within my function.  How does the following, from the CRBasic help file, apply?

By default, pointer variables are of type Long, but they can be typed using Float!, Long!, Boolean!, or String! (e.g., Dim P as Float!). If pointers are not typed, the summation of the values pointed to truncates the floats before the addition.

Also, how would I handle an array within the function?  Does the pointer offset have to be scaled for each successive array element by the size of that element?

Please log in or register to comment.