53 votes

Comment formater un pointeur de fonction?

Est-il possible d'imprimer un pointeur vers une fonction en C ANSI? Bien sûr, cela signifie que vous devez lancer la fonction de pointeur de pointeur void, mais il semble que c'est pas possible??

#include <stdio.h>

int main() {
    int (*funcptr)() = main;

    printf("%p\n", (void* )funcptr);
    printf("%p\n", (void* )main);

    return 0;
}

$ gcc-ansi -pedantic -Wall test.c -o test
test.c: Dans la fonction 'main':
test.c:6: avertissement: ISO C interdit de conversion de pointeur de fonction pour objet de type pointeur
test.c:7: avertissement: ISO C interdit de conversion de la fonction de pointeur de pointeur d'objet type
$ ./test
0x400518
0x400518

C'est "travail", mais non-standard...

50voto

caf Points 114951

La seule façon de le faire est de l'accès des octets qui composent le pointeur à l'aide d'un type de caractère. Comme ceci:

#include <stdio.h>

int main() {
    int (*funcptr)() = main;
    unsigned char *p = (unsigned char *)&funcptr;
    int i;

    for (i = 0; i < sizeof funcptr; i++)
    {
        printf("%02x ", p[i]);
    }
    putchar('\n');

    return 0;
}

Beaucoup les jeux de mots le pointeur de fonction en tant que void *, ou de tout non type de caractère, comme dreamlax la réponse ne, est un comportement indéterminé.

Ce que ces octets qui composent le pointeur de fonction en fait moyenne est dépendant de l'implémentation. Ils pourraient représenter un index dans une table de fonctions, par exemple.

4voto

Dustin Points 1268

Il y a l'utilisation des syndicats qui peut se déplacer à l'avertissement/d'erreur, mais le résultat est toujours (très probablement) un comportement indéfini:

#include <stdio.h>

int
main (void)
{
  union
  {
    int (*funcptr) (void);
    void *objptr;
  } u;
  u.funcptr = main;

  printf ("%p\n", u.objptr);

  return 0;
}

Vous pouvez comparer deux pointeurs de fonction (par exemple, printf ("%i\n", (main == funcptr));) à l'aide d'une instruction if pour tester si elles sont égales ou pas (je sais qui va à l'encontre de l'objet et pourrait très bien être hors de propos), mais dans la mesure où effectivement la sortie de l'adresse du pointeur de fonction, ce qui se passe est le fournisseur de votre plate-forme cible C de la bibliothèque et de votre compilateur.

1voto

Joseph Quinsey Points 4450

Avec gcc 4.3.4, à l'aide de commutateurs -O2 -Wstrict-aliasing, dreamlax réponse produira:

warning: dereferencing type-punned pointer will break strict-aliasing rules

Ajouté: je pense que les objections à la caf réponse sur boutisme et la taille sont raisonnables, ce qui sa solution n'a pas d'adresse (no pun intended). Dustin suggestion pour l'utilisation d'une union fonte est probablement juridique (bien que de ce que j'ai lu il semble y avoir un débat, mais votre compilateur n'est important que la loi). Mais son code peut être simplifié (ou occulté, selon votre goût) par le one-liner:

printf("%p\n", ((union {int (*from)(void); void *to;})funcptr).to);

Cela supprime la gcc strict-aliasing avertissement (mais est-elle correcte?).

Agrégation des moulages de ne pas "travailler", si vous utilisez le pédant commutateur, ou à l'aide par exemple, SGI IRIX, de sorte que vous aurez besoin d'utiliser:

printf("%p\n", ((union {int (*from)(void); void *to;} *)&funcptr)->to);

Mais en ce qui concerne la question d'origine: elle trouve son origine dans l'utilisation de pédant, je pense que c'est un peu pédant :).

En outre edit: Remarque vous ne pouvez pas utiliser principal dans le dernier exemple, comme dans:

printf("%p\n", ((union {int (*from)(void); void *to;})   main).to);  // ok
printf("%p\n", ((union {int (*from)(void); void *to;} *)&main)->to); // wrong!

parce que, naturellement, &main se désintègre au principal.

1voto

dan04 Points 33306

Convertissez le pointeur de fonction en un entier, puis convertissez-le de nouveau en un pointeur pour utiliser "% p".

 #include <stdio.h>

int main() {
    int (*funcptr)() = main;

    printf("%p\n", (void *)(size_t) funcptr);
    printf("%p\n", (void *)(size_t) main);

    return 0;
}
 

Notez que sur certaines plates-formes (par exemple DOS 16 bits dans les modèles de mémoire "moyenne" ou "compacte"), les pointeurs vers les données et les pointeurs vers les fonctions ne sont pas de la même taille.

1voto

Michael Buen Points 20453

Essaye ça:

 #include <stdio.h>
#include <inttypes.h>


int main() {
    int (*funcptr)() = main;
    unsigned char *p = (unsigned char *)&funcptr;
    int i;

    /* sample output: 00000000004005e0 */
    printf("%016"PRIxPTR"\n", (uintptr_t)main);
    /* sample output: 00000000004005e0 */
    printf("%016"PRIxPTR"\n", (uintptr_t)funcptr);

    /* reflects the fact that this program is running on little-endian machine
    sample output: e0 05 40 00 00 00 00 00 */
    for (i = 0; i < sizeof funcptr; i++)
    {
        printf("%02x ", p[i]);
    }
    putchar('\n');

    return 0;
}
 

Utilisé ces drapeaux:

 gcc -ansi -pedantic -Wall -O2 -Wstrict-aliasing c.c
 

Aucun avertissement émis à l'aide de ces drapeaux

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X