J’ai lu que convertir un pointeur fonction vers un pointeur de données et vice versa fonctionne sur la plupart des plates-formes, mais n’est pas garanti pour travailler. Pourquoi est-ce le cas ? Ne devrait pas être simplement des adresses dans la mémoire principale tant par conséquent être compatible ?
Réponses
Trop de publicités?Une architecture ne doit pas stocker de code et les données dans la même mémoire. Avec une architecture Harvard, code et les données sont stockées dans la mémoire complètement différent. Plupart des architectures sont les architectures Von Neumann avec code et les données dans la mémoire même, mais C ne limite pas elle-même à seulement certains types d’architectures si possible.
Certains ordinateurs ont (eu) des espaces d'adressage différents pour le code et les données. Sur de tels matériels, il ne fonctionne tout simplement pas.
Le langage est conçu non seulement pour le courant des applications de bureau, mais pour lui permettre d'être mis en œuvre sur une large gamme de matériel.
Il semble que le langage C comité n'a jamais voulu void*
être un pointeur de fonction, ils voulaient juste un pointeur générique d'objets.
Le C99 Justification dit:
6.3.2.3 Pointeurs
C a maintenant été mis en œuvre sur une large gamme d'architectures. Alors que certains de ces architectures fonction uniforme des pointeurs qui sont de la taille de certains de type entier, au maximum code portable ne peut assumer aucune correspondance nécessaire entre les différents types de pointeur et les types d'entiers. Dans certaines implémentations, les pointeurs peuvent même être plus large que n'importe quel type entier.L'utilisation de l'
void*
("pointeurvoid
") comme un objet générique type de pointeur est une invention de la C89 Comité. L'Adoption de ce type a été stimulée par le désir de spécifier prototype de fonction des arguments que soit tranquillement convertir arbitraire des pointeurs (comme enfread
) ou de se plaindre si le type d'argument ne correspond pas exactement (enstrcmp
). Rien n'est dit sur les pointeurs de fonctions, qui peuvent être sans commune mesure avec les pointeurs d'objet et/ou des entiers.
Remarque , Rien n'est dit sur les pointeurs de fonctions dans le dernier paragraphe. Ils pourraient être différents des autres pointeurs, et le comité est conscient de cela.
Pour ceux qui se souviennent de MS-DOS, Windows 3.1 et plus la réponse est assez facile. L'ensemble de ces utilisés à l'appui de plusieurs différents modèles de mémoire, avec différentes combinaisons de caractéristiques pour le code et les données des pointeurs.
Ainsi, par exemple, pour le modèle Compact (petit code, de données de grande taille):
sizeof(void *) > sizeof(void(*)())
et à l'inverse, dans le modèle Moyen (grand code, de données de petite taille):
sizeof(void *) < sizeof(void(*)())
Dans ce cas, vous n'avez pas de stockage séparé pour le code et la date, mais ne pouvait toujours pas de conversion entre les deux pointeurs (court de l'utilisation non-standard __près de et __ _ _ loin de modificateurs).
En outre, il n'y a aucune garantie que même si les pointeurs sont de la même taille, qu'ils pointent vers la même chose dans le DOS Petit modèle de mémoire, à la fois le code et les données utilisées près de pointeurs, mais ils ont souligné les différents segments. Si la conversion d'un pointeur de fonction à un pointeur de données ne serait pas vous donner un pointeur qui ont une relation à la fonction, et il n'y a donc pas d'utilisation d'une telle conversion.
Pointeurs void sont censés pour être en mesure d’accueillir un pointeur vers n’importe quel genre de données--mais pas nécessairement un pointeur à une fonction. Certains systèmes ont des exigences différentes pour des pointeurs vers des fonctions que des pointeurs vers des données (par exemple, il existe DSP avec adressage différent pour les données vs code, moyen modèle sur MS-DOS utilisé pointeurs 32 bits pour le code mais seuls pointeurs 16 bits pour les données).
En plus de ce qui est déjà dit ici, il est intéressant de regarder POSIX dlsym()
:
Le C ISO norme n'exige pas que les pointeurs de fonctions peut être jeté en arrière et en avant pour des pointeurs vers les données. En effet, la norme ISO C standard ne nécessite pas qu'un objet de type void * peut contenir un pointeur à une fonction. Les implémentations de soutenir l'extension XSI, cependant, ne nécessitent qu'un objet de type void * peut contenir un pointeur à une fonction. Le résultat de la conversion d'un pointeur à une fonction en un pointeur vers un autre type de données (à l'exception de void *) n'est toujours pas défini, cependant. Notez que les compilateurs conformes à la norme ISO C standard sont nécessaires pour générer une alerte si une conversion à partir d'un void * pointeur vers un pointeur de fonction est tenté, comme dans:
fptr = (int (*)(int))dlsym(handle, "my_function");
En raison du problème de noter ici, une version ultérieure peut soit ajouter une nouvelle fonction pour renvoyer des pointeurs de fonction, ou de l'interface actuelle peut être dépréciée en faveur de deux nouvelles fonctions: l'une qui renvoie les pointeurs de données et l'autre qui renvoie des pointeurs de fonction.