La taille des pointeurs peut-elle varier entre les pointeurs de données et de fonction?

Je viens de lire la section de la FAQ C sur les pointeurs .

Il explique qu’il est impossible d’utiliser des pointeurs void * pour conserver des pointeurs de fonction, car les pointeurs vers des données et des pointeurs vers des fonctions peuvent avoir des tailles différentes sur certaines plates-formes et que void * est uniquement garanti suffisant pour contenir des pointeurs vers des données.

Quelqu’un peut-il donner un exemple de plate-forme où les pointeurs vers les données et les pointeurs vers des fonctions ont des tailles différentes?

 > type ppp.c #include  #include  int global = 0; int main(void) { int local = 0; static int staticint = 0; int *mall; int (*fx)(void); fx = main; mall = malloc(42); /* assume it worked */ printf("#sizeof pointer to local: %d\n", (int)sizeof &local); printf("#sizeof pointer to static: %d\n", (int)sizeof &staticint); printf("#sizeof pointer to malloc'd: %d\n", (int)sizeof mall); printf("#sizeof pointer to global: %d\n", (int)sizeof &global); printf("#sizeof pointer to main(): %d\n", (int)sizeof fx); free(mall); return 0; } > tcc -mc ppp.c Turbo C Version 2.01 ... warnings about unused variables elided ... Turbo Link Version 2.0 ... > ppp #sizeof pointer to local: 4 #sizeof pointer to static: 4 #sizeof pointer to malloc'd: 4 #sizeof pointer to global: 4 #sizeof pointer to main(): 2 > tcc -mm ppp.c > ppp #sizeof pointer to local: 2 #sizeof pointer to static: 2 #sizeof pointer to malloc'd: 2 #sizeof pointer to global: 2 #sizeof pointer to main(): 4 

tcc -mc génère du code dans le modèle “compact”; tcc -mm génère du code dans le modèle “moyen”

En mode réel x86, les codes et les données sont accessibles par segment + décalage, chacun représentant une quantité de 16 bits. Les pointeurs “proches” étaient en 16 bits uniquement et utilisaient le segment actuel, les pointeurs “Loin” en 32 bits et spécifiaient le segment et l’offset. Pour les compilateurs C, vous pouviez choisir plusieurs modèles de mémoire, avec des valeurs par défaut différentes pour les pointeurs proche et lointain du code et des données.

Par exemple, le modèle de mémoire “Moyen” utilisé par défaut près des pointeurs pour les données, mais loin pour le code.

Je ne serais pas surpris si certains processeurs embarqués modernes ont des modèles de mémoire similaires.

Les microcontrôleurs PIC 16 bits (Microchip PIC24 et dsPIC) sont des exemples de dispositifs d’architecture Harvard avec différentes tailles de pointeurs d’espace de données et de code. La taille des espaces d’adresse distincts est différente. La SRAM sur puce a un coût plus élevé pour la zone de puce que la mémoire Flash. Elle est beaucoup moins coûteuse et les pointeurs de données peuvent donc être plus petits.

Ceci est également vrai pour les architectures PIC12, PIC16 et PIC18 également, mais dsPIC est ce que j’utilise par hasard.

Notez que POSIX exige que les pointeurs sur les objects et les fonctions sur des fonctions aient la même taille:

2.12.3 Types de pointeur

Tous les types de pointeurs de fonction doivent avoir la même représentation que le pointeur de type sur void. La conversion d’un pointeur de fonction en void * ne modifie pas la représentation. Une valeur void * résultant d’une telle conversion peut être reconvertie dans le type de pointeur de fonction d’origine, à l’aide d’une conversion explicite, sans perte d’informations.

Remarque: La norme ISO C ne l’impose pas, mais elle est indispensable à la conformité POSIX.

Par conséquent, les systèmes qui prétendent être conformes à POSIX seront uniformes. Si vous ne ciblez que de telles machines, vous n’avez pas à vous soucier des différences.

Les machines qui utilisent une architecture Harvard disposent d’un stockage séparé pour les instructions et les données et, en conséquence, d’un espace adresse distinct pour les instructions et les données. Dans une telle architecture, il n’y a pas de vraie raison pour que les deux espaces adresse (ou la mémoire physique les sauvegardant) aient la même taille.

C’est une situation de “dépend”. En C ++, je rappelle que les pointeurs de fonction membres sont en réalité de deux pointeurs, mais cela peut n’être qu’un détail d’implémentation.

Dans certains des très vieux systèmes pré-PC, la taille du pointeur peut également dépendre de ce qui est référencé (mais vous pouvez aussi avoir des caractères de 11 bits: D)