BREF RÉSUMÉ
(que je mettrai également en haut):
(0) Le fait de considérer les pointeurs comme des adresses est souvent un bon outil d'apprentissage et constitue souvent l'implémentation réelle des pointeurs vers des types de données ordinaires.
(1) Mais sur de nombreux compilateurs, peut-être la plupart, les pointeurs vers les fonctions ne sont pas des adresses, mais sont plus gros qu'une adresse (généralement 2x, parfois plus), ou sont en fait des pointeurs vers une structure en mémoire qui contient les adresses de fonction et des trucs comme une piscine constante.
(2) Les pointeurs vers les membres de données et les pointeurs vers les méthodes sont souvent encore plus étranges.
(3) Code x86 hérité avec problèmes de pointeurs FAR et NEAR
(4) Plusieurs exemples, notamment l'IBM AS / 400, avec des "gros pointeurs" sécurisés.
Je suis sûr que vous pouvez en trouver plus.
DÉTAIL:
UMMPPHHH !!!!! Jusqu'à présent, la plupart des réponses sont des réponses "programmeur weenie" assez typiques - mais pas le compilateur weenie ni le matériel weenie. Puisque je fais semblant d'être un weenie matériel et que je travaille souvent avec des weenies de compilateur, permettez-moi de mettre mes deux cents:
Sur de nombreux compilateurs C, probablement la plupart, un pointeur vers des données de type T
est, en fait, l'adresse de T
.
Bien.
Mais, même sur beaucoup de ces compilateurs, certains pointeurs ne sont PAS des adresses. Vous pouvez le constater en regardant sizeof(ThePointer)
.
Par exemple, les pointeurs vers les fonctions sont parfois beaucoup plus gros que les adresses ordinaires. Ou, ils peuvent impliquer un niveau d'indirection. Cet articlefournit une description, impliquant le processeur Intel Itanium, mais j'en ai vu d'autres. En règle générale, pour appeler une fonction, vous devez connaître non seulement l'adresse du code de la fonction, mais également l'adresse du pool constant de la fonction - une région de mémoire à partir de laquelle les constantes sont chargées avec une seule instruction de chargement, plutôt que le compilateur doive générer une constante 64 bits sur plusieurs instructions Load Immediate et Shift et OR. Ainsi, plutôt qu'une seule adresse 64 bits, vous avez besoin de 2 adresses 64 bits. Certains ABI (Application Binary Interfaces) le déplacent sur 128 bits, tandis que d'autres utilisent un niveau d'indirection, le pointeur de fonction étant en fait l'adresse d'un descripteur de fonction qui contient les 2 adresses réelles qui viennent d'être mentionnées. Ce qui est mieux? Dépend de votre point de vue: performances, taille du code, et certains problèmes de compatibilité - le code suppose souvent qu'un pointeur peut être converti en un long ou un long long, mais peut également supposer que le long long est exactement 64 bits. Ce code n'est peut-être pas conforme aux normes, mais les clients peuvent néanmoins souhaiter qu'il fonctionne.
Beaucoup d'entre nous ont des souvenirs douloureux de l'ancienne architecture segmentée Intel x86, avec NEAR POINTERs et FAR POINTERS. Heureusement, ils sont presque éteints maintenant, donc seulement un bref résumé: en mode réel 16 bits, l'adresse linéaire réelle était
LinearAddress = SegmentRegister[SegNum].base << 4 + Offset
Alors qu'en mode protégé, il peut être
LinearAddress = SegmentRegister[SegNum].base + offset
l'adresse résultante étant vérifiée par rapport à une limite définie dans le segment. Certains programmes n'utilisaient pas vraiment les déclarations de pointeur C / C ++ FAR et NEAR standard, mais beaucoup venaient de le dire *T
--- mais il y avait des commutateurs de compilation et de l'éditeur de liens donc, par exemple, les pointeurs de code pouvaient être des pointeurs proches, juste un décalage de 32 bits par rapport à tout ce qui se trouve dans le registre CS (Code Segment), tandis que les pointeurs de données peuvent être des pointeurs FAR, spécifiant à la fois un numéro de segment de 16 bits et un décalage de 32 bits pour une valeur de 48 bits. Maintenant, ces deux quantités sont certainement liées à l'adresse, mais comme elles ne sont pas de la même taille, laquelle est l'adresse? De plus, les segments comportaient également des autorisations - lecture seule, lecture-écriture, exécutable - en plus des éléments liés à l'adresse réelle.
Un exemple plus intéressant, à mon humble avis, est (ou était peut-être) la famille IBM AS / 400. Cet ordinateur a été l'un des premiers à implémenter un OS en C ++. Les pointeurs sur ce machime étaient généralement 2X la taille réelle de l'adresse - par exemple, comme cette présentationdit, des pointeurs de 128 bits, mais les adresses réelles étaient de 48 à 64 bits, et, encore une fois, des informations supplémentaires, ce qu'on appelle une capacité, qui fournissait des autorisations telles que la lecture, l'écriture, ainsi qu'une limite pour éviter le débordement de la mémoire tampon. Oui: vous pouvez le faire de manière compatible avec C / C ++ - et si cela était omniprésent, le PLA chinois et la mafia slave ne pirateraient pas autant de systèmes informatiques occidentaux. Mais historiquement, la plupart des programmes C / C ++ ont négligé la sécurité pour les performances. Plus intéressant encore, la famille AS400 a permis au système d'exploitation de créer des pointeurs sécurisés, qui pourraient être attribués à du code non privilégié, mais que le code non privilégié ne pouvait ni falsifier ni altérer. Encore une fois, la sécurité et, bien que conforme aux normes, le code C / C ++ non conforme aux normes, très bâclé, ne fonctionnera pas dans un système aussi sécurisé. Encore une fois, il existe des normes officielles,
Maintenant, je vais quitter ma boîte à savon de sécurité et mentionner quelques autres façons dont les pointeurs (de différents types) ne sont souvent pas vraiment des adresses: pointeurs vers les membres de données, pointeurs vers les méthodes de fonctions membres et leurs versions statiques sont plus grandes qu'un adresse ordinaire. Comme le dit ce post :
Il existe de nombreuses façons de résoudre ce problème [problèmes liés à l'héritage simple ou multiple et à l'héritage virtuel]. Voici comment le compilateur Visual Studio décide de le gérer: Un pointeur vers une fonction membre d'une classe à héritage multiplié est vraiment une structure. "Et ils continuent en disant" Casting un pointeur de fonction peut changer sa taille! ".
Comme vous pouvez probablement le deviner à partir de mon pontificat sur la (in) sécurité, j'ai été impliqué dans des projets matériels / logiciels C / C ++ où un pointeur était traité plus comme une capacité qu'une adresse brute.
Je pourrais continuer, mais j'espère que vous comprenez l'idée.
BREF RÉSUMÉ
(que je mettrai également en haut):
(0) considérer les pointeurs comme des adresses est souvent un bon outil d'apprentissage et constitue souvent la mise en œuvre réelle des pointeurs vers des types de données ordinaires.
(1) Mais sur de nombreux compilateurs, peut-être la plupart, les pointeurs vers des fonctions ne sont pas des adresses, mais sont plus gros qu'une adresse (généralement 2X, parfois plus), ou sont en fait des pointeurs vers une structure en mémoire qui contient les adresses de fonction et des trucs comme une piscine constante.
(2) Les pointeurs vers les membres de données et les pointeurs vers les méthodes sont souvent encore plus étranges.
(3) Code x86 hérité avec problèmes de pointeurs FAR et NEAR
(4) Plusieurs exemples, notamment l'IBM AS / 400, avec des "gros pointeurs" sécurisés.
Je suis sûr que vous pouvez en trouver plus.