50
votes

Is there any way to print a pointer to a function in ANSI C? Of course this means you have to cast the function pointer to void pointer, but it appears that's not 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: In function 'main':
test.c:6: warning: ISO C forbids conversion of function pointer to object pointer type
test.c:7: warning: ISO C forbids conversion of function pointer to object pointer type
$ ./test
0x400518
0x400518

It's "working", but non-standard...

6
Well, I was about to accept an answer that worked, until it got deleted (although it made no sense).L̲̳o̲̳̳n̲̳̳g̲̳̳p̲̳o̲̳̳k̲̳̳e̲̳̳
Can you typecast it to an int (or 64-bit int on larger systems) and print that instead?Michael Dorgan
@Michael Dorgan: Casting a pointer to an integer type other than intptr_t or uintptr_t is implementation-defined, however implementing these types is optional according to the standard.dreamlax
@Longpoke: Sorry for deleting my answer, I wasn't sure whether it would satisfy your compiler flags so I temporarily removed it just in case it wouldn't.dreamlax
What i was looking for was a legal way to do it, and yours seems legal, and the compiler shuts up too, so thanks :)L̲̳o̲̳̳n̲̳̳g̲̳̳p̲̳o̲̳̳k̲̳̳e̲̳̳

6 Answers

49
votes

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

Examining the bytes of the function pointer with an lvalue of type void *, or any non character type, 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; or they could even be the first N characters of the function's name which is looked up in the symbol table when you call through the function pointer. The only operations that need be supported on a function pointer are calling the function through it and comparison against another function pointer or NULL for strict equality/inequality, so there is very wide latitude available in how they are implemented.

5
votes

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.

2
votes

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.

2
votes

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

2
votes

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.

0
votes

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