How to format a function pointer?

喜你入骨 提交于 2019-11-26 13:21:17
caf

The only legal way to do this is to access the bytes making up the pointer using a character type. Like this:

#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;
}

Punning the function pointer as a void *, or any non character type, as dreamlax's answer does, is undefined behaviour.

What those bytes making up the function pointer actually mean is implementation-dependent. They could just represent an index into a table of functions, for example.

There's the use of unions that can get around the warning/error, but the result is still (most likely) undefined behavior:

#include <stdio.h>

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

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

  return 0;
}

You can compare two function pointers (e.g. printf ("%i\n", (main == funcptr));) using an if statement to test whether they're equal or not (I know that completely defeats the purpose and could very well be irrelevant), but as far as actually outputting the address of the function pointer, what happens is up to the vendor of your target platform's C library and your compiler.

Cast the function pointer to an integer, then cast it to a pointer again to use "%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;
}

Note that on some platforms (e.g. 16-bit DOS in the "medium" or "compact" memory models), pointers to data and pointers to functions are not the same size.

Try this:

#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;
}

Used this flags:

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

No warnings emitted using those flags

With gcc 4.3.4, using switches -O2 -Wstrict-aliasing, dreamlax's answer will produce:

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

Added: I think the objections to caf's answer about endianness and size are reasonable, which his solution does not address (no pun intended). Dustin's suggestion for using a union cast is probably legal (although from what I read there seems to be some debate, but your compiler does is important than the law). But his code could be simplified (or obfuscated, depending on your taste) by the one-liner:

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

This removes the gcc strict-aliasing warning (but is it 'correct'?).

Aggregate casts won't 'work' if you are using the -pedantic switch, or are using e.g. SGI IRIX, so you'll need to use:

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

But regarding the original question: its origin lies in the use of -pedantic, which I think is slightly pedantic :).

Further edit: Note you cannot use main in the last example, as in:

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

because of course &main decays to main.

I'm not sure if this is kosher but it achieves the effect without a loop, unions, casts to non-pointer types, or extra dependencies besides string.h

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

No warnings with gcc -ansi -pedantic -Wall -Wstrict-aliasing on GCC 7.1.1

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!