How to format a function pointer?

CFunction Pointers

C Problem Overview


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...

C Solutions


Solution 1 - C

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.

Solution 2 - C

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.

Solution 3 - C

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.

Solution 4 - C

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.

Solution 5 - C

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

Solution 6 - C

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

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionL̲̳o̲̳̳n̲̳̳g̲̳̳p̲̳o̲̳̳k̲̳̳e̲̳̳View Question on Stackoverflow
Solution 1 - CcafView Answer on Stackoverflow
Solution 2 - CDustinView Answer on Stackoverflow
Solution 3 - CJoseph QuinseyView Answer on Stackoverflow
Solution 4 - Cdan04View Answer on Stackoverflow
Solution 5 - CMichael BuenView Answer on Stackoverflow
Solution 6 - CJon DeatonView Answer on Stackoverflow