significado pointer arithmetic and c pointers printf c99

pointer - ¿Cuál es el uso correcto de printf para mostrar los indicadores rellenos con 0s



pointers in c pdf (9)

Como su enlace ya sugiere, el comportamiento no está definido. No creo que haya una forma portátil de hacerlo, ya que el% p depende de la plataforma en la que estés trabajando. Por supuesto, puedes simplemente lanzar el puntero a un int y mostrarlo en hex:

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

En C, me gustaría utilizar printf para mostrar los punteros, y para que se alineen correctamente, me gustaría rellenarlos con ceros.

Creo que la forma correcta de hacerlo fue:

printf("%016p", ptr);

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

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

He buscado en Google un poco, y el siguiente hilo trata sobre el mismo tema, pero realmente no da una solución.

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

Al leerlo, parece que la razón por la que gcc se queja es porque la sintaxis que sugerí no está definida en C99. Pero parece que no puedo encontrar otra forma de hacer lo mismo de una manera estándar aprobada.

Entonces aquí está la doble pregunta:

  • ¿Tengo entendido que este comportamiento no está definido por el estándar C99?
  • Si es así, ¿existe una forma estándar aprobada y portátil de hacerlo?

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

por lo que se convertiría en:

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


Esta respuesta es similar a la dada anteriormente en https://.com/a/1255185/1905491 pero también tiene en cuenta los posibles anchos (como se describe en https://.com/a/6904396/1905491 que no lo reconocí hasta que mi respuesta fue presentada debajo de él;). El siguiente recorte imprimirá punteros como 8 caracteres hexadecimales pasados ​​en máquinas sanas * donde se pueden representar mediante 32 bits, 16 en 64b y 4 en sistemas 16b.

#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 carácter de asterisco para obtener el ancho por el siguiente argumento, que está en C99 (¿probablemente antes?), Pero que rara vez se ve "en la naturaleza". Esto es mucho mejor que usar la conversión p porque este último está definido por la implementación.

* El estándar permite que uintptr_t sea ​​mayor que el mínimo, pero supongo que no hay implementación que no use el mínimo.


La única forma portátil de imprimir valores de puntero es usar el especificador "%p" , que produce resultados definidos por la implementación. (Es probable que la conversión a uintptr_t y el uso de PRIxPTR funcione, pero (a) uintptr_t se introdujo en C99, por lo que algunos compiladores pueden no uintptr_t , y (b) no se garantiza que exista incluso en C99 (es posible que no haya un tipo de entero lo suficientemente grande como para contener todos los posibles valores de puntero.

Por lo tanto, utilice "%p" con sprintf() (o snprintf() , si lo tiene) para imprimir en una cadena, y luego imprima el relleno de cadena con espacios en blanco iniciales.

Un problema es que no hay una forma realmente buena de determinar la longitud máxima de la cadena producida por "%p" .

Esto es un inconveniente (aunque, por supuesto, puede envolverlo en una función). Si no necesita una portabilidad del 100%, nunca he usado un sistema para convertir el puntero a unsigned long e imprimir el resultado con "0x%16lx" no funcionaría. [ ACTUALIZACIÓN : Sí, tengo. Windows de 64 bits tiene punteros de 64 bits y unsigned long 32 bits.] (O puede usar "0x%*lx" y calcular el ancho, probablemente algo como sizeof (void*) * 2 Si realmente está paranoico , puede contabilizar sistemas donde CHAR_BIT > 8 , por lo que obtendrá más de 2 dígitos hexadecimales por byte).


Quizás esto sea interesante (desde una máquina de Windows de 32 bits, usando 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 puede ver, la versión% p rellena con ceros el tamaño de un puntero, y luego espacios al tamaño especificado, mientras que el uso de% x y los moldes (los moldes y el especificador de formato son altamente imposibles de usar) utiliza solo ceros.


Tenga en cuenta que si el puntero se imprime con el prefijo "0x", deberá sustituir "% 018p" para compensar.


Usualmente uso% x para mostrar los punteros. Supongo que no es portátil para sistemas de 64 bits, pero funciona bien para 32 bits.

Me interesaría ver qué respuestas hay para las soluciones portátiles , ya que la representación del puntero no es exactamente portátil.


Utilizar:

#include <inttypes.h> printf("0x%016" PRIXPTR "/n", (uintptr_t) pointer);

O use otra variante de las macros de ese encabezado.

También tenga en cuenta que algunas implementaciones de printf() imprimen un '' 0x '' delante del puntero; otros no (y ambos son correctos de acuerdo con el estándar C).


#include <inttypes.h>

#include <stdint.h>

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

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