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

Mi conjetura es que la manera correcta de hacer esto era:

printf("%016p", ptr);

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

advertencia: '0' bandera de usa con '%p' gnu_printf formato

He buscado en google un poco para él, y el siguiente hilo es sobre el mismo tema, pero realmente no da una solución.

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

De la lectura, parece que la razón por la que gcc se queja es que la sintaxis me sugirió que no está definido en C99. Pero me parece que no puede encontrar otra manera de hacer la misma cosa en una norma aprobada manera.

Así que aquí está la doble pregunta:

  • Es mi entendimiento correcto que este comportamiento no está definido por el estándar C99?
  • Si es así, hay una norma aprobada, portátil manera de hacerlo?
  • Peor advertencia nunca. Debe ser eliminado de gcc en mi humilde opinión.
InformationsquelleAutor | 2009-08-10

9 Comentarios

  1. 38

    #include <inttypes.h>

    #include <stdint.h>

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

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

    • Interesante. Esta es la primera vez que veo este PRIxPTR notación. Es esta norma, o gcc específico? Si estándar, el estándar? C89 o C99?
    • Estándar en C99. La macro PRIxPTR se define en <inttypes.h>. El uintptr_t tipo está definido en <stdint.h>.
    • Permítanme asegúrese de que tengo esta recta. La razón por lo que traté de hacer, no es portable es debido a que no todas las plataformas de visualización punteros como 0x….. Porque de este relleno con ceros (0) no es portable. Por otro lado, printf(«%016″PRIxPTR», (uintptr_t)ptr); en todas las plataformas de impresión de mi puntero con el derecho de longitud, formado como un 0x… número, se rellenan con ceros (0), sin inseguro de fundición.
    • A la derecha. Pero que dependen de C99 — los compiladores de Microsoft y aplicaciones de apoyo a mal por lo que he leído aquí y en otros lugares (soy un tipo Unix), y algunos de gcc embalaje para Windows reutilizar el tiempo de ejecución de Microsoft. Por CIERTO, usted no conseguirá el prefijo 0x (ponga usted mismo o utilizar un # bandera, pero tenga en cuenta que la bandera no es de los punteros que se convierten en 0 — generalmente punteros NULL).
    • Hace sentido. Y como De C89, no hay ningún portátil manera de hacerlo?
    • Era una práctica bastante común en C89 asumir que unsigned long fue capaz contiene un puntero sin pérdida. Microsoft rompió la práctica la elección de la LLP64 de 64 bits de Windows (mientras que todos los otros sistemas sé de que había elegido LP64 o incluso ILP64 años antes). Así que yo sepa no hay forma de asegurarse de que funciona en los sistemas comunes. La definición de su propio inttypes.h es probablemente la cosa más fácil de hacer (después de todo, esa posibilidad es una razón probable de que no hay macros y no nuevo formato para el stdint.h tipos).
    • Pero, ¿qué es BEAF?
    • una de las palabras de escritura usando sólo letras que son dígito hexadecimal (ver nedbatchelder.com/text/hexwords.html).
    • Supongamos que yo quería collar de 8 dígitos en un sistema con punteros de 32 bits y de 16 dígitos en un sistema con punteros de 64 bits. ¿Hay alguna forma fácil de hacerlo?
    • PRIxPTR»\n», (uintptr_t)ptr); con PTDISPLAYWIDTH una macro expansión a «8» o «16» dependiendo del tipo de sistemas que están en.
    • No debería ser DEAD:BEEF?
    • usted me hizo entender Artelius comentario.

  2. 8

    Uso:

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

    O utilizar otra variante de las macros de ese encabezado.

    También tenga en cuenta que algunas implementaciones de printf() imprimir un ‘0x‘ en frente de el puntero; otros no (y ambas son correctas de acuerdo con el estándar de C).

    • Tenga en cuenta que formalmente usted necesita para lanzar a uintptr_t.
    • Yup – gracias por el recordatorio. Fijo en la respuesta.
    • O usted podría utilizar "%#016" PRIxPTR lugar, la # dice para mostrar la base octal y hexadecimal.
    • tienes razón – se podría utilizar el ‘#’, pero que imprime 0x01ab o 0X01AB y no me gusta cualquiera de las notaciones: me gusta 0x01AB. Lo que escribí me pone lo que me gusta y no lo que no me gusta.
  3. 5

    La única portátil manera de imprimir los valores de puntero es el uso de la "%p" especificador, que produce la implementación de salida predefinidos. (La conversión a uintptr_t y el uso de PRIxPTR es probable que funcione, pero (a) uintptr_t se introdujo en C99, por lo que algunos compiladores no pueden admitir, y (b) no garantiza que existe incluso en C99 (no podría ser de tipo entero suficientemente grande para contener todos los posibles valores de puntero.

    Para uso "%p" con sprintf() (o snprintf(), si la tiene) para imprimir una cadena y, a continuación, imprimir la cadena de relleno con los espacios en blanco iniciales.

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

    Este es sin duda un inconveniente (aunque, por supuesto, usted puede envolver en una función). Si usted no necesita el 100% de la portabilidad, yo nunca he usado un sistema estaban echando el puntero a unsigned long e imprimir el resultado utilizando "0x%16lx" no iba a funcionar. [ACTUALIZACIÓN: Sí, tengo. Windows de 64 bits tiene punteros de 64 bits y 32 bits unsigned long.] (O puede utilizar "0x%*lx" y calcular el ancho, probablemente algo como sizeof (void*) * 2. Si eres muy paranoico, se puede dar cuenta de los sistemas donde CHAR_BIT > 8, por lo que voy a obtener más de 2 dígitos hexadecimales por byte.)

    • El problema que encuentro con esta sugerencia: casting the pointer to unsigned long and print... using "0x%16x" es que usted está operando una advertencia para otro. Al menos para mí, este se deshace de la advertencia de la 0 indicador utilizado con %p pero luego me sale una warning: cast from pointer to integer of different size [-Wpointer-to-int-cast] lugar.
    • Me sugirió que sólo para el caso en que ni "%p" ni uintptr_t está disponible.
    • Hay una que cumple con los estándares camino, que es el uso de PRIxPTR. Si usted elige utilizar un compilador que no se ajustan a C99, como el MSVC de 2011, le toca a usted para averiguar cómo hacerlo, probablemente con un #ifdef. No creo que MSVC se ajusta a C89 totalmente.
    • Tenga en cuenta que en Windows de 64 bits, el tipo de unsigned long es todavía una de 32 bits la cantidad, a pesar de que los punteros son de 64 bits. El uso de 0x%16lx fallaría en Win64, por lo tanto, usted siempre iba a obtener 8 ceros a la izquierda. En principio, el uso de unsigned long long y 0x%16llx iba a funcionar — MS VS 2015 tiempo de ejecución admite el ll modificador; también utiliza I64 para indicar números de 64 bits (printf() especificadores de formato). Comprobar si las versiones anteriores compatibles ll antes de usarlo.
    • Yo creo que otro portátil enfoque sería escribir una función que almacena el puntero en un void* y, a continuación escribe sizeof (void*) bytes hexadecimales de partida en la dirección de (no) ese puntero.
    • ¿Qué acerca de peso?…
    • Quien/lo que sea, va a ser la lectura de la salida se necesita saber cómo es el formato. Tener direcciones consecutivas representado como FF5F3412 y 00603412 podría no ser lo más conveniente para los humanos el análisis de 12345FFF y 12346000 podría ser, pero sería no obstante ser una útil representación de un ser humano que entiende, o para un programa que tendría que volver a leer la dirección, mientras que el objeto está todavía vivo. Tener una opción de bytes de salida en orden inverso podría ser muy útil, pero sería entonces el riesgo de confusión si las rutinas de salida y la de leer de nuevo los punteros se configuran de manera diferente.
    • Bueno, tal vez establecer que los punteros son sólo para ser leídos en la misma plataforma, o un estándar de peso (redes recogido big endian)
    • Si la dirección de algunos útiles objeto pasa a tener un patrón de bits representados por bytes hexadecimales 12,34,56,78, entonces dentro de ese particular, la ejecución del programa, a menos que o hasta que el tiempo de vida del objeto termina, un puntero formado a partir de bytes hexadecimales 12,34,56,78 va a identificar ese objeto. Que en particular puntero del patrón de bits tendría ningún significado para el código portable en cualquier otro contexto.
    • Bien, sin duda, sería confuso para quien está tratando de depurar el programa para ver como direcciones, sobre todo porque a veces necesitamos comparar las direcciones (que yo necesitaba hacer que el día de ayer en realidad)

  4. 4

    Esta respuesta es similar a la dada anteriormente en https://stackoverflow.com/a/1255185/1905491 pero también toma la anchos en cuenta (como se indica por https://stackoverflow.com/a/6904396/1905491 que no me reconoce hasta que mi respuesta fue rendido por debajo de ella ;). El siguiente cortada imprimirá punteros como 8 0-pasado caracteres hexadecimales en sane* máquinas donde se puede estar representado por 32 bits, 16 de 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);

    Nota el uso del asterisco para obtener el ancho y por el siguiente argumento, que es en C99 (probablemente antes?), pero que es bastante rara vez visto «en la naturaleza». Esto es mucho mejor que el uso de la p la conversión, porque el último es de aplicación definido.

    * El estándar permite uintptr_t a ser mayor que el mínimo, pero supongo que no hay ninguna aplicación que no utilice la mínima.

    • Pregunta ingenua: ¿no #define PRIxPTR_WIDTH ((int)(sizeof(void*)*2)) trabajo, incluso si uintptr_t es mayor que el mínimo?
    • «Trabajo» como en compilar y ejecutar, sí, pero sería la impresión innecesaria de los ceros a la izquierda.
  5. 0

    Es fácil de resolver si lanzas un puntero a un tipo long. El problema es que esto no funcionará en todas las plataformas, ya que asume que un puntero se puede ajustar dentro de un tiempo, y que un puntero puede ser visualizada en 16 caracteres (64 bits). Sin embargo, esto es cierto en la mayoría de plataformas.

    por lo que sería:

    printf("%016lx", (unsigned long) ptr);
    • Yo no tengo el derecho de la máquina / OS a la mano para confirmar, pero creo que en windows de 64 bits, los punteros son de 64 bits al mismo tiempo que son de 32 bits, rompiendo su suposición. Así que, a menos que me equivoco, lo que sugiere que podrían romper en al menos uno de los principales de la plataforma.
    • Si la portabilidad a windows es importante, confiar en las características de C99 no es probablemente la cosa para hacer.
    • normalmente en una plataforma de 64 bits, enteros de 32 bits y anhela son de 64 bits. Si esto es un problema en su uso de la plataforma de un largo, largo.
    • En realidad, creo que los punteros de un garantizados para caber dentro de un tiempo. La única aplicación que no es conforme a esto es MSVC (64-bit).
    • Nota mi comment acerca de Windows de 64 bits; esto no va a funcionar allí.
  6. 0

    Como su enlace sugiere ya, el comportamiento es indefinido. Yo no creo que haya un portátil manera de hacer esto como %p depende de la plataforma en el que estás trabajando. Usted podría, por supuesto, acaba de lanzar el puntero a int y mostrar en hexadecimal:

    printf("0x%016lx", (unsigned long)ptr);
    • Nota mi comment acerca de Windows de 64 bits; esto no va a funcionar allí.
  7. 0

    Tal vez esto va a ser interesante (desde un windows de 32 bits de la máquina, el uso de mingw):

    [email protected] /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;
    }
    
    [email protected] /u
    $ gcc -Wall -o test test.c
    test.c: In function `main':
    test.c:7: warning: `0' flag used with `%p' printf format
    
    [email protected] /u
    $ ./test.exe
    p:         0022FF77
    x: 000000000022ff77

    Como se puede ver, el %p versión rellena con ceros para el tamaño de un puntero y, a continuación, espacios para el tamaño especificado, mientras que el uso de %x y moldes (de los moldes y el especificador de formato son muy transportables) utiliza sólo ceros.

    • Interesante. Se confirma que el %de 016p» no es portable, ya que en mi máquina (de linux de 64 bits) es almohadillas de puramente con 0, no con espacios.
    • Eso no es un bug, simplemente una característica inesperada. 😉 Lo del casting para un valor de 64 bits en una arquitectura de 32 bits.
    • El elenco de unsigned long antes de la refundición de unsigned long long rompe si sizeof(unsigned long) != sizeof(unsigned long long), como en Windows de 64 bits.
  8. 0

    Tenga en cuenta que si el puntero se imprime con el «0x» prefijo, tendría que sustituir «%018p» para compensar.

  9. -1

    Normalmente utilizo %x para mostrar los punteros. Supongo que no es portable para sistemas de 64 bits, pero funciona bien para 32-bitter.

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

    • Mi sistema principal es en realidad una de 64-bits, por lo %x realmente no se corte. Para evitar este tipo de problema es la razón por la que quiero usar %p.
    • %#016lx debería funcionar en cualquier sistema de su sobre, un puntero está garantizado para caber dentro de un tiempo. (Creo) por CIERTO que es la letra ‘l’ no 1 el número antes de la ‘x’.
    • D – VS2005 no está de acuerdo. Me da advertencias acerca de la posible perdida de datos, a menos que use algo como ULONG_PTR lugar. Véase también el comentario dejado por AProgrammer sobre la aceptada respuesta. Por supuesto VS no es exactamente lo que se conoce como un modelo de cumplimiento de la…
    • Ah, se me olvidaba mencionar el hecho de que no funciona en 64 bits MSVC. Creo que el la versión de 32-bit y 64-bit versión advertir de ello.

Dejar respuesta

Please enter your comment!
Please enter your name here