web-dev-qa-db-fra.com

Comment formater un pointeur de fonction?

Est-il possible d'imprimer un pointeur sur une fonction en ANSI C? Bien sûr, cela signifie que vous devez convertir le pointeur de fonction en pointeur vide, mais il semble que ce ne soit 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 la conversion d'un pointeur de fonction en type de pointeur d'objet
test.c: 7: avertissement: ISO C interdit la conversion d'un pointeur de fonction en un type de pointeur d'objet
$ ./test
0x400518
0x400518

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

La seule façon légale de le faire est d'accéder aux octets constituant le pointeur en utilisant un type de caractère. Comme ça:

#include <stdio.h>

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

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

    return 0;
}

Utiliser le pointeur de fonction en tant que void *, ou tout type de caractère autre que caractère, comme la réponse de dreamlax le fait }, est un comportement indéfini.

En réalité, les octets constituant le pointeur de la fonction mean dépendent de la mise en oeuvre. Ils pourraient simplement représenter un index dans une table de fonctions, par exemple.

41
caf

Il y a l'utilisation de syndicats qui peuvent contourner l'avertissement/l'erreur, mais le résultat reste le comportement (le plus probable) non dé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));) en utilisant une instruction if pour vérifier si elles sont égales ou non (je sais que cela irait à l'encontre de l'objectif recherché et pourrait très bien ne pas être pertinent), mais dans la mesure du résultat de l'adresse pointeur, ce qui se passe appartient au vendeur de la bibliothèque C de votre plate-forme cible et à votre compilateur.

5
Dustin

Transformez le pointeur de fonction en un entier, puis redéfinissez-le en pointeur pour qu'il utilise "% 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, le DOS 16 bits dans les modèles de mémoire "moyenne" ou "compacte"), les pointeurs sur les données et les pointeurs sur les fonctions ne sont pas de la même taille.

2
dan04

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é cette drapeaux:

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

Aucun avertissement émis à l'aide de ces drapeaux

1
Michael Buen

Je ne suis pas sûr que ce soit casher, mais cela permet d'obtenir l'effet sans boucle, unions, conversions vers des types sans pointeur, ou dépendances supplémentaires en plus de string.h

int (*funcptr)() = main;
void* p = NULL;
memcpy(&p, (void**) &funcptr, sizeof(funcptr));
printf("%p", p);

Aucun avertissement avec gcc -ansi -pedantic -Wall -Wstrict-aliasing sur GCC 7.1.1

0
Jon Deaton