Pregunta

En C, me gustaría usar printf para mostrar punteros, y para que se alineen correctamente, me gustaría a ellos almohadilla con 0s.

Mi suposición era que la forma correcta de hacer esto era:

printf("%016p", ptr);

Esto funciona, pero esto gcc se queja con el mensaje siguiente:

warning: '0' flag used with ‘%p’ gnu_printf format

He buscado en Google un poco de ella, y el siguiente hilo está en el mismo tema, pero en realidad no se dé una solución.

http://gcc.gnu.org/ml/ gcc-bugs / 2003-05 / msg00484.html

Al leerlo, parece que la razón por gcc se queja es que la sintaxis sugerí no está definido en C99. Pero me parece que no puede encontrar ninguna otra manera de hacer lo mismo de una manera estándar aprobado.

Así que aquí es la doble pregunta:

  • ¿Es mi entendimiento correcto que este comportamiento no está definido por la norma C99?
  • Si es así, ¿existe una norma aprobada manera, portátil de hacer esto?
¿Fue útil?

Solución

#include <inttypes.h>

#include <stdint.h>

printf("%016" PRIxPTR "\n", (uintptr_t)ptr);

pero no se imprimirá el puntero en la forma definida aplicación (dice DEAD:BEEF de 8086 modo segmentado).

Otros consejos

Uso:

#include <inttypes.h>

printf("0x%016" PRIXPTR "\n", (uintptr_t) pointer);

O utilizar otra variante de las macros de esa cabecera.

Tenga en cuenta también que algunas implementaciones de printf() imprimir un '0x' delante del puntero; otros no lo hacen (y ambos son correctos de acuerdo con la norma C).

La única manera portátil para imprimir valores de puntero es utilizar el especificador "%p", lo que produce una salida definida por la implementación. (Conversión a uintptr_t y usando PRIxPTR es probable que funcione, pero (a) uintptr_t fue introducido en C99, por lo que algunos compiladores puede no soportar, y (b) que no está garantizado que existir incluso en C99 (puede que no haya un tipo entero lo suficientemente grande para contener todos los posibles valores de puntero.

Así que utilice "%p" con sprintf() (o snprintf(), si lo tiene) para imprimir en una cadena, y luego imprimir el relleno cadena con espacios a la izquierda.

Uno de los problemas es que no hay realmente una buena manera de determinar la longitud máxima de la serie producida por "%p".

Este es ciertamente un inconveniente (aunque por supuesto se puede envolver en una función). Si usted no necesita la portabilidad% 100, nunca he utilizado un sistema se haya emitido el puntero a unsigned long e imprimir el resultado utilizando "0x%16lx" no funcionaría. [ Actualizar : Sí, tengo. Windows de 64 bits tiene punteros de 64 bits y de 32 bits unsigned long.] (O puede utilizar "0x%*lx" y calcular el ancho, probablemente algo así como sizeof (void*) * 2. Si usted es realmente paranoico, que puede dar cuenta de los sistemas en los CHAR_BIT > 8, por lo que' ll obtener más de 2 dígitos hexadecimales por byte.)

Esta respuesta es similar a la dada anteriormente en https://stackoverflow.com/a/1255185/1905491 sino que también tiene las posibles anchuras en cuenta (como se indica por https://stackoverflow.com/a/6904396/1905491 que no reconocí hasta que mi respuesta se hizo por debajo de ella;). Los siguientes cortó imprimirá punteros como 8 caracteres hexadecimales pasaron-0 en máquinas sanos * donde pueden ser representados por 32 bits, 16 en 64b y 4 en 16b sistemas.

#include <inttypes.h>
#define PRIxPTR_WIDTH ((int)(sizeof(uintptr_t)*2))

printf("0x%0*" PRIxPTR, PRIxPTR_WIDTH, (uintptr_t)pointer);

Tenga en cuenta el uso del asterisco a buscar el ancho por el siguiente argumento, que está en C99 (probablemente antes?), Pero que es bastante rara vez se ve "en la naturaleza". Esto es mucho mejor que el uso de la conversión p ya que este último es definido por la implementación.

* La norma permite uintptr_t sea más grande que el mínimo, pero supongo que no hay aplicación que no utiliza el mínimo.

Es fácil de resolver si lanzas el puntero a un tipo largo. El problema es que esto no funcionará en todas las plataformas, ya que supone un puntero puede caber dentro de un tiempo, y que un puntero se puede mostrar en 16 caracteres (64 bits). Esto es cierto, sin embargo en la mayoría de las plataformas.

por lo que se convertiría en:

printf("%016lx", (unsigned long) ptr);

A medida que su enlace ya sugiere, el comportamiento es indefinido. No creo que haya una manera portátil de hacer esto como% p a su vez depende de la plataforma que está trabajando. Se podría, por supuesto, sólo echó el puntero a un int y mostrarlo en hexadecimal:

printf("0x%016lx", (unsigned long)ptr);

Tal vez esto será interesante (desde una máquina Windows de 32 bits, utilizando MinGW):

rjeq@RJEQXPD /u
$ cat test.c
#include <stdio.h>

int main()
{
    char c;

    printf("p: %016p\n", &c);
    printf("x: %016llx\n", (unsigned long long) (unsigned long) &c);

    return 0;
}

rjeq@RJEQXPD /u
$ gcc -Wall -o test test.c
test.c: In function `main':
test.c:7: warning: `0' flag used with `%p' printf format

rjeq@RJEQXPD /u
$ ./test.exe
p:         0022FF77
x: 000000000022ff77

Como se puede ver, las pastillas de la versión% p con ceros al tamaño de un puntero y, a continuación espacios al tamaño especificado, mientras que el uso de x% y moldes (los moldes y especificador de formato son altamente no portables) utiliza sólo ceros.

Tenga en cuenta que si las impresiones de puntero con el prefijo "0x", que tendrían que sustituir "% 018p" para compensar.

Yo suelo usar% x para mostrar punteros. Supongo que no es portátil para sistemas de 64 bits, pero funciona bien para 32-amargos.

Voy a estar interesado en ver qué respuestas hay para soluciones portátiles , ya que la representación del puntero no es exactamente portátil.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top