En lisant un article décrivant les différences entre OO et la programmation fonctionnelle, je suis tombé sur des pointeurs de fonction. Cela fait un moment que je n'ai pas obtenu mon diplôme en informatique (2003) et j'ai donc cherché des pointeurs pour rafraîchir ma mémoire.
Les pointeurs sont des variables qui contiennent une référence à une adresse mémoire. Ils peuvent être considérés comme pointant vers les données contenues dans cette adresse mémoire si ces données existent. Ou, comme dans le cas de l'article, ils peuvent indiquer le point d'entrée d'une section de code et peuvent être utilisés pour appeler ce code.
Pourquoi est-ce différent d'une variable? Les variables sont des noms symboliques pour les adresses mémoire et les compilateurs remplaceront le nom par l'adresse réelle. Cela signifie que les variables contiennent des références à des emplacements de mémoire et peuvent être considérées comme pointant vers les données à cette adresse si de telles données existent.
Si la différence réside dans le comportement (peut-être qu'un pointeur ne peut pas être réaffecté au moment de l'exécution ou ne peut être affecté qu'à un nom de variable symbolique, pas à une autre valeur), cela ne signifie-t-il pas qu'il s'agit simplement d'une variable d'un type particulier, le type de pointeur? De la même manière, une variable déclarée de type entier est limitée par la compilation dans laquelle elle peut être utilisée.
Qu'est-ce que j'oublie ici?
la source
Réponses:
Votre question est intéressante à plusieurs égards, car elle nécessite des distinctions soigneuses pour plusieurs questions. Mais votre vision me semble essentiellement correcte. Je n'ai pas lu votre référence avant d'avoir écrit la plupart de cette réponse pour éviter de biaiser ma réponse.
Tout d'abord, votre affirmation
Variables are symbolic names for memory addresses
, elle est presque correcte, mais confond le concept et sa mise en œuvre habituelle. Une variable est en fait juste un conteneur qui peut contenir une valeur qui peut être modifiée. Habituellement, ce conteneur est implémenté sur un ordinateur comme un bloc d'espace mémoire, caractérisé par une adresse et une taille car les variables peuvent contenir des objets qui nécessitent des représentations avec plus ou moins d'informations.Mais je considérerai surtout un point de vue plus abstrait de la sémantique des langages, indépendamment des techniques d'implémentation.
Les variables ne sont donc que des conteneurs d'un point de vue abstrait. Un tel conteneur n'a pas besoin d'avoir un nom. Cependant, les langues ont souvent des variables qui sont nommées en leur associant un identifiant, de sorte que les utilisations de la variable peuvent être exprimées par l'identifiant. Une variable peut en fait avoir plusieurs identifiants via différents mécanismes d'alias. Une variable peut également être une sous-partie d'une variable plus grande: un exemple est une cellule d'une variable de tableau, qui peut être nommée en spécifiant la variable de tableau et l'index de la cellule, mais pourrait également être associée à des identifiants via l'aliasing.
J'utilise délibérément le mot container qui est quelque peu neutre, pour éviter d'invoquer d'autres mots qui peuvent être chargés sémantiquement techniquement. Il est en fait proche du concept de référence décrit dans wilipedia , qui est souvent confondu avec une adresse mémoire. Le mot pointeur lui - même est souvent compris comme une adresse mémoire, mais je ne pense pas que cela soit significatif lorsque l'on considère la plupart des langages de haut niveau, et probablement inapproprié dans le document de discussion auquel vous vous référez (bien que les adresses puissent être utilisées), car il est inapproprié se référant à une mise en œuvre spécifique. Cependant, il convient à un langage comme C, qui est censé être beaucoup plus proche des concepts d'implémentation et de l'architecture de la machine.
En fait, si vous regardez des variables ou des valeurs au niveau de l'implémentation, il peut y avoir plusieurs systèmes complexes d'indirection, de "pointeurs de niveau machine", mais qui sont (et devraient être) invisibles pour l'utilisateur, de sorte que le point de vue abstrait Je développe peut être valable. Pour la plupart des langages de programmation, l'utilisateur ne devrait pas avoir à s'inquiéter, ni même à connaître, la mise en œuvre, car la mise en œuvre peut varier considérablement pour un langage donné. Cela peut ne pas être vrai pour certains langages, tels que C, qui sont intentionnellement proches de l'architecture de la machine, en tant que substitut avancé des langages d'assemblage qui sont en relation presque directe avec le codage binaire explicite, mais d'un niveau beaucoup trop bas pour une utilisation pratique dans la plupart des cas. situations.
Ce que l'utilisateur d'une langue doit savoir, et parfois même moins, c'est ce que sont les valeurs et les opérations associées, où elles peuvent être contenues, comment elles peuvent être associées aux noms, comment fonctionne le système de nommage, comment définir des types de valeurs, etc.
Un autre concept important est donc les identifiants et les noms. Nommer une entité (une valeur) peut se faire en associant un identifiant à une valeur (généralement dans une déclaration). Mais une valeur peut également être obtenue en appliquant des opérations à d'autres valeurs nommées. Les noms peuvent être réutilisés et il existe des règles (règles de portée) pour déterminer ce qui est associé à un identifiant donné, selon le contexte d'utilisation. Il existe également des noms spéciaux, appelés littéraux, pour nommer les valeurs de certains domaines, tels que les entiers (par exemple ) ou booléens (par exemple true ).612
L'association d'une valeur immuable avec un identifiant est généralement appelée une constante. Les littéraux sont des constantes dans ce sens.
Les "conteneurs de valeurs" peuvent également être considérés comme des valeurs, et leur association avec un identifiant est une variable au sens "naïf" habituel que vous avez utilisé. Vous pourriez donc dire qu'une variable est une "constante de conteneur".
Maintenant, vous vous demandez peut-être quelle est la différence entre associer un identifiant à une valeur (déclaration de constante) ou affecter une valeur à une variable, c'est-à-dire stocker la valeur dans le conteneur défini comme constante de conteneur. Essentiellement, la déclaration peut être vue comme une opération qui définit une notation, qui associe un identifiant qui est une entité syntaxique à une valeur qui est une entité sémantique. L'affectation est une opération purement sémantique qui modifie un état, c'est-à-dire modifie la valeur d'un conteneur. Dans un certain sens, la déclaration est un méta-concept sans effet sémantique, autre que la fourniture d'un mécanisme de nommage (c'est-à-dire syntaxique) pour les entités sémantiques.
En fait, les affectations sont des opérations sémantiques qui se produisent dynamiquement lors de l'exécution du programme, tandis que les déclarations ont une nature plus syntaxique et doivent généralement être interprétées dans le texte du programme, indépendamment de l'exécution. C'est pourquoi la portée statique (c'est-à-dire la portée textuelle) est généralement le moyen naturel de comprendre la signification des identificateurs.
Après tout cela, je peux dire qu'une valeur de pointeur n'est qu'un autre nom pour un conteneur, et une variable de pointeur est une variable de conteneur, c'est-à-dire un conteneur (constant) qui peut contenir un autre conteneur (avec des limitations possibles sur le jeu contenant imposées par certains système de type).
Concernant le code, vous déclarez
[pointers] might indicate the entry point to a section of code and can be used to call that code
. En fait, ce n'est pas tout à fait vrai. Une section de code est souvent dénuée de sens seule (d'un point de vue de haut niveau ou d'implémentation). D'un point de vue de haut niveau, le code contient généralement des identifiants, et vous devez interpréter ces identifiants dans le contexte statique où ils ont été déclarés. Mais il existe en fait une duplication possible du même contexte statique, due essentiellement à la récursivité qui est un phénomène dynamique (au moment de l'exécution), et le code ne peut être exécuté que dans une instance dynamique appropriée du contexte statique. C'est un peu complexe, mais la conséquence est que le concept approprié est celui d'une fermeture qui associe un morceau de code et un environnement où les identifiants doivent être interprétés. La fermeture est le concept sémantique approprié, c'est-à-dire une valeur sémantique correctement définissable. Ensuite, vous pouvez avoir des constantes de fermeture, des variables de fermeture,Une fonction est une fermeture, généralement avec certains paramètres pour définir ou initialiser certaines de ses entités (constantes et variables).
Je saute de nombreuses variations sur les utilisations de ces mécanismes.
Les fermetures peuvent être utilisées pour définir des structures OO dans des langages impératifs ou fonctionnels. En fait, les premiers travaux sur le style OO (probablement avant le nom) ont été effectués de cette façon.
Le document auquel vous faites référence, que j'ai parcouru rapidement, semble être intéressant, rédigé par une personne compétente, mais peut-être pas une lecture facile si vous n'avez pas une expérience significative avec une variété de langues et leurs modèles de calcul sous-jacents.
Mais rappelez-vous: beaucoup de choses sont aux yeux du spectateur, tant qu'il conserve une vision cohérente. Les points de vue peuvent différer.
Est-ce que cela répond à votre question?
PS: C'est une longue réponse. Si vous considérez qu'une partie de celle-ci est inadéquate, veuillez être explicite sur ce qu'elle est. Je vous remercie.
la source
La différence est par définition et par application, un pointeur est une variable spécialisée pour contenir une adresse mémoire d'une autre variable; en termes OO, un pointeur serait peut-être considéré comme héritant de son comportement d'une classe générale appelée variable.
la source