la respuesta más simple, suponiendo que no le importa los caprichos y las variaciones de formatos entre diferentes plataformas, es el %p
notación estándar.
El estándar C99 (ISO/IEC 9899: 1999) dice en §7.19.6.1 ¶8:
p
El argumento será un puntero a void
. El valor del puntero es convertido a una secuencia de caracteres de impresión, en una manera definida por la implementación .
(En C11 - ISO/IEC 9899: 2011 - La información está en §7.21.6.1 ¶8.)
En algunas plataformas, que incluirá un líder 0x
y en otros no lo hará , y las letras podrían estar en minúsculas o en mayúsculas, y el estándar C ni siquiera define que será una salida hexadecimal aunque no conozco ninguna implementación donde no lo esté.
Es un poco abierto debatir si debe convertir explícitamente los punteros con un molde (void *)
.Está siendo explícito, lo que generalmente es bueno (así que es lo que hago), y el estándar dice 'el argumento debe ser un puntero al void
'. En la mayoría de las máquinas, se saldría con la omisión de un lanzamiento explícito. Sin embargo, importaría en una máquina donde la representación de bits de una dirección char *
para una ubicación de memoria dada es diferente de la dirección 'cualquier otro puntero' para la misma ubicación de memoria. Esta sería una máquina dirigida por palabra, en lugar de byte. Estas máquinas no son comunes (probablemente no estén disponibles) en estos días, pero la primera máquina en la que trabajé después de la universidad fue una de esas (ICL Perq).
Si no está satisfecho con el comportamiento definido por la implementación de %p
, a continuación, utilizar C99 <inttypes.h>
y uintptr_t
lugar:
printf("0x%" PRIXPTR "\n", (uintptr_t)your_pointer);
Esto le permite ajustar con precisión la representación a tu gusto. Elegí tener los dígitos hexadecimales en mayúscula para que el número sea uniformemente de la misma altura y aparezca la inclinación característica al inicio de 0xA1B2CDEF
, no como 0xa1b2cdef
, que también se inclina hacia arriba y hacia abajo a lo largo del número. Tu elección, sin embargo, dentro de límites muy amplios. La conversión de (uintptr_t)
es recomendada inequívocamente por GCC cuando puede leer la cadena de formato en tiempo de compilación. Creo que es correcto solicitar el elenco, aunque estoy seguro de que hay algunos que ignorarían la advertencia y saldrían con la suya la mayor parte del tiempo.
kerrek pregunta en los comentarios:
estoy un poco confundido acerca de las promociones estándar y argumentos variadic. ¿Todos los punteros se promocionan de forma estándar a void *? De lo contrario, si int*
fueran, digamos, dos bytes, y void*
fueran 4 bytes, entonces sería claramente un error leer cuatro bytes del argumento, ¿no?
que estaba bajo la ilusión de que el estándar de C dice que todos los punteros a objetos deben ser del mismo tamaño, por lo void *
y int *
no pueden ser de diferentes tamaños. Sin embargo, lo que creo que es la sección pertinente de la norma C99 no es tan enfático (aunque no sé de una aplicación donde lo que he sugerido es cierto en realidad es falsa):
§6.2.5 Tipos
¶26 Un puntero a void tendrá los mismos requisitos de representación y alineación que un puntero a un tipo de carácter. 39) De forma similar, los punteros a versiones calificadas o no calificadas de tipos compatibles deben tener los mismos requisitos de representación y alineación. Todos los punteros a tipos de estructura deben tener los mismos requisitos de representación y alineación entre sí. Todos los punteros a tipos de unión tendrán los mismos requisitos de representación y alineación entre sí. Los punteros a otros tipos no necesitan tener los mismos requisitos de representación o alineación.
39) Los mismos requisitos de representación y alineación implican la intercambiabilidad como argumentos para funciones, valores devueltos de funciones y miembros de uniones.
(C11 dice exactamente lo mismo en la sección §6.2.5, ¶28, y la nota al pie 48.)
Por lo tanto, todos los punteros a las estructuras deben ser del mismo tamaño que los demás, y deben compartir los mismos requisitos de alineación, aunque las estructuras señaladas por los punteros pueden tener requisitos de alineación diferentes. Del mismo modo para los sindicatos. Los punteros de caracteres y los punteros vacíos deben tener los mismos requisitos de tamaño y alineación. Los punteros a las variaciones en int
(es decir, unsigned int
y signed int
) deben tener los mismos requisitos de tamaño y alineación que los demás; similarmente para otros tipos. Pero el estándar C no dice formalmente que sizeof(int *) == sizeof(void *)
. Oh, bueno, SO es bueno para hacerte inspeccionar tus suposiciones.
El estándar C definitivamente no requiere que los punteros a las funciones sean del mismo tamaño que los punteros a objetos. Eso fue necesario para no romper los diferentes modelos de memoria en sistemas similares a DOS. Allí podría tener punteros de datos de 16 bits pero punteros de función de 32 bits, o viceversa. Esta es la razón por la cual el estándar C no exige que los punteros a las funciones se puedan convertir a punteros a objetos y viceversa.
Afortunadamente (para los programadores y dirigidos POSIX), POSIX pasos en la brecha y hace el mandato de que los punteros de función y los punteros de datos son del mismo tamaño:
§2.12.3 Pointer Types
Todos los tipos de puntero de función tendrá la misma representación que el puntero de tipo para anular. La conversión de un puntero de función a void *
no alterará la representación. Un valor de void *
resultante de dicha conversión puede convertirse de nuevo al tipo de puntero de función original, utilizando un molde explícito, sin pérdida de información.
Nota: El estándar ISO C no lo requiere, pero se requiere para la conformidad con POSIX.
Por lo tanto, parece que conversiones explícitas a void *
son muy aconsejable para la máxima fiabilidad en el código cuando se pasa un puntero a una función variadic como printf()
. En sistemas POSIX, es seguro lanzar un puntero a un puntero vacío para imprimir. En otros sistemas, no es necesariamente seguro hacer eso, ni es necesariamente seguro pasar punteros que no sean void *
sin un molde.
Estoy un poco confundido acerca de las promociones estándar y los argumentos variados. ¿Todos los punteros se promocionan de forma estándar a 'void *'? De lo contrario, si 'int *' fuera, por ejemplo, dos bytes, y 'void *' fueran 4 bytes, entonces sería claramente un error leer cuatro bytes del argumento, ¿no? –
Tenga en cuenta que una actualización de POSIX (POSIX 2013) ha eliminado la sección 2.12.3, moviendo la mayoría de los requisitos a ['dlsym()'] (http://pubs.opengroup.org/onlinepubs/9699919799/functions/dlsym .html) en su lugar. Algún día escribiré el cambio ... pero 'un día' no es 'hoy'. –
¿Esta respuesta también se aplica a los punteros a las funciones? ¿Pueden convertirse a 'void *'? Hmm, veo tu comentario [aquí] (http://stackoverflow.com/questions/9053658/correct-format-specifier-to-print-pointer-address#comment11360489_9053677). Como solo se necesita una conversión de un wat (puntero de función a 'void *'), ¿funciona entonces? – chux