¿Cómo formatear un puntero de función?

¿Hay alguna forma de imprimir un puntero a una función en ANSI C? Por supuesto, esto significa que debe convertir el puntero de la función en un puntero vacío, pero parece que no es posible.

#include  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: en la función ‘main’:
test.c: 6: advertencia: ISO C prohíbe la conversión del puntero de función al tipo de puntero de objeto
test.c: 7: advertencia: ISO C prohíbe la conversión del puntero de función al tipo de puntero de objeto
$ ./test
0x400518
0x400518

Está “funcionando”, pero no es estándar …

La única forma legal de hacerlo es acceder a los bytes que componen el puntero utilizando un tipo de carácter. Me gusta esto:

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

Sacar el puntero de la función como un void * , o cualquier tipo que no sea de carácter, como lo hace la respuesta de Dreamlax , es un comportamiento indefinido.

Lo que los bytes que componen el puntero a la función realmente significan depende de la implementación. Simplemente podrían representar un índice en una tabla de funciones, por ejemplo.

Existe el uso de sindicatos que pueden evitar la advertencia / error, pero el resultado es aún (más probable) comportamiento indefinido:

 #include  int main (void) { union { int (*funcptr) (void); void *objptr; } u; u.funcptr = main; printf ("%p\n", u.objptr); return 0; } 

Puede comparar dos punteros de función (por ejemplo, printf ("%i\n", (main == funcptr)); ) usando una instrucción if para comprobar si son iguales o no (sé que eso derrota por completo el propósito y podría muy bueno, será irrelevante), pero en cuanto a la salida de la dirección del puntero a la función, lo que sucede depende del proveedor de la biblioteca C de su plataforma objective y de su comstackdor.

Eche el puntero a un entero y luego vuélvalo a un puntero para usar “% p”.

 #include  int main() { int (*funcptr)() = main; printf("%p\n", (void *)(size_t) funcptr); printf("%p\n", (void *)(size_t) main); return 0; } 

Tenga en cuenta que en algunas plataformas (por ejemplo, DOS de 16 bits en los modelos de memoria “mediana” o “compacta”), los punteros a los datos y los punteros a las funciones no tienen el mismo tamaño.

Prueba esto:

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

Usó estas banderas:

 gcc -ansi -pedantic -Wall -O2 -Wstrict-aliasing cc 

No se emitieron advertencias con esas banderas

Con gcc 4.3.4, usando los conmutadores -O2 -Wstrict-aliasing, la respuesta de dreamlax producirá:

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

Agregado: Creo que las objeciones a la respuesta de caf sobre endianness y tamaño son razonables, que su solución no aborda (sin juego de palabras). La sugerencia de Dustin de usar un elenco sindical es probablemente legal (aunque por lo que he leído, parece que hay algo de debate, pero el comstackdor sí es importante que la ley). Pero su código podría ser simplificado (u ofuscado, según su gusto) por el one-liner:

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

Esto elimina la advertencia de aliasing estricto de gcc (¿pero es ‘correcto’?).

Los moldes agregados no “funcionarán” si está utilizando el interruptor -pedantic, o está usando, por ejemplo, SGI IRIX, por lo que deberá usar:

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

Pero con respecto a la pregunta original: su origen está en el uso de -pedantic, que creo que es ligeramente pedante :).

Edición adicional: tenga en cuenta que no puede usar main en el último ejemplo, como en:

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

porque por supuesto y decaimientos principales a main .

No estoy seguro si esto es kosher pero logra el efecto sin un bucle, uniones, lanzamientos a tipos no punteros o dependencias adicionales además de string.h

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

No hay advertencias con gcc -ansi -pedantic -Wall -Wstrict-aliasing en GCC 7.1.1