pointer - ¿Cómo formatear un puntero de función?
ptr function c (6)
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 compilador 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 .
¿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 <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: 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 ...
Eche el puntero a un entero y luego vuélvalo a un puntero para usar "% 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;
}
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.
Existe el uso de sindicatos que pueden evitar la advertencia / error, pero el resultado es aún (más probable) comportamiento indefinido:
#include <stdio.h>
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 objetivo y de su compilador.
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 <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;
}
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.
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
Prueba esto:
#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;
}
Usó estas banderas:
gcc -ansi -pedantic -Wall -O2 -Wstrict-aliasing c.c
No se emitieron advertencias con esas banderas