1

I am wondering if this is a portable way to print function pointers.
Casting the function pointer directly to unsigned char * is non-portable.

/* writehex() prints the given byte as its hex representation to the given FILE * */
extern void writehex(FILE *, const unsigned char);

/* Theoretical printf() implementation. */
int printf(const char *format, ...) {

    ...

    void (*fptr)(void);
    const unsigned char *bytes = (const unsigned char *) &fptr;
    size_t i;

    fptr = va_arg(ap, ((void)(*)(void)));
    for (i = 0; i < sizeof(fptr); ++i)
        writehex(stdout, *bytes++);

    ...
}

cbot
  • 117
  • 6
  • 2
    based on the question in your title, this is how you [`printf` a pointer](https://stackoverflow.com/questions/30354097/how-to-printf-a-memory-address-in-c). But not sure what you're showing in code,, trying to roll your own functionality? – yano Feb 26 '22 at 04:44
  • 3
    The wrapper struct isn't necessary. The address of a function pointer is still an object pointer. – dbush Feb 26 '22 at 04:47
  • @dbush my bad. I'll change it to make it more clear. – cbot Feb 26 '22 at 05:45

1 Answers1

1

Casting a function pointer to void * or other pointer to objects may lose information as the function pointer may be wider.

There is no great way to portably print function pointers - a shortcoming of C.

Alternatives:

Convert to a wide integer

Try the widest.

if (sizeof function_pointer <= sizeof(uintmax_t)) {
  printf("0x%jX\n", (uintmax_t) function_pointer);
}

Memory dump (OP's approach)

Note that padding and endian issues are in play. Output may include additional junk and unexcepted order, yet this will always "work" in that it is portable and compliant.

"Casting the function pointer directly to unsigned char * is non-portable." does not apply here as it is OK to cast the address of a function pointer to a void *

else {
  unsigned char buf[sizeof(function_pointer)];
  memcpy(buf, &function_pointer, sizeof buf);
  printf("0x");
  for (unsigned i=0; i<sizeof buf; i++) {
    printf("%02X", buf[i]);
  }
  printf("\n");
}

  printf("0x");
  for (unsigned i = 0; i

  printf("0x%jX\n", (uintmax_t) function_pointer);
}
  

Consider the wider variety of architectures, the text output from printing function pointers has very different interpretations across implementations.

chux - Reinstate Monica
  • 143,097
  • 13
  • 135
  • 256
  • Can printing a void * also have different interpretations across implementations also? Wouldn't endian and padding issues also apply to void *? – cbot Feb 26 '22 at 06:13
  • Re “Casting a function pointer to `void *` or other pointer to _objects_”: Why start with this sentence? The code in the question does not cast a function pointer to a pointer to an object type and acknowledges doing so is not portable. – Eric Postpischil Feb 26 '22 at 11:14
  • @cbot Yes, printing a `void *` also has different interpretations across implementations. The same bit pattern for a `void *` printed with `printf("%p\n", void_pointer)` may print `0x12345` on one system, `0x1234:0005` on another system, and `Red:2345` on a 3rd. It is implementation dependent. – chux - Reinstate Monica Feb 26 '22 at 13:19
  • @EricPostpischil To re-affirm OP's non-portable understanding., – chux - Reinstate Monica Feb 26 '22 at 13:21
  • @EricPostpischil because I do not want people to give me the answer 'cast it to a void * and pass it to printf() with %p' which I have seen from other questions. I am trying to write a printf() routine in kernelspace and printing function addresses is useful. I wanted to confirm that this is a portable way to do it because I do not want to have to write a routine to print function pointers for each architecture. – cbot Feb 26 '22 at 17:00