Cómo imprimir de forma portátil un tipo int64_t en C

8 minutos de lectura

avatar de usuario de rtacconi
rtacconi

El estándar C99 tiene tipos enteros con tamaño de bytes como int64_t. estoy usando Windows %I64d formato actualmente (o sin firmar %I64u), me gusta:

#include <stdio.h>
#include <stdint.h>
int64_t my_int = 999999999999999999;
printf("This is my_int: %I64d\n", my_int);

y me sale esta advertencia del compilador:

warning: format ‘%I64d’ expects type ‘int’, but argument 2 has type ‘int64_t’

Probé con:

printf("This is my_int: %lld\n", my_int); // long long decimal

Pero recibo la misma advertencia. Estoy usando este compilador:

~/dev/c$ cc -v
Using built-in specs.
Target: i686-apple-darwin10
Configured with: /var/tmp/gcc/gcc-5664~89/src/configure --disable-checking --enable-werror --prefix=/usr --mandir=/share/man --enable-languages=c,objc,c++,obj-c++ --program-transform-name=/^[cg][^.-]*$/s/$/-4.2/ --with-slibdir=/usr/lib --build=i686-apple-darwin10 --program-prefix=i686-apple-darwin10- --host=x86_64-apple-darwin10 --target=i686-apple-darwin10 --with-gxx-include-dir=/include/c++/4.2.1
Thread model: posix
gcc version 4.2.1 (Apple Inc. build 5664)

¿Qué formato debo usar para imprimir la variable my_int sin tener una advertencia?

  • Para C++, consulte stackoverflow.com/questions/8132399/how-to-printf-uint64-t

    – Antonio

    23 de agosto de 2016 a las 9:02

avatar de usuario de ouah
ouah

Para int64_t escribe:

#include <inttypes.h>
int64_t t;
printf("%" PRId64 "\n", t);

por uint64_t escribe:

#include <inttypes.h>
uint64_t t;
printf("%" PRIu64 "\n", t);

también puedes usar PRIx64 para imprimir en hexadecimal.

cppreference.com tiene una lista completa de macros disponibles para todos los tipos incluyendo intptr_t (PRIxPTR). Hay macros separadas para scanf, como SCNd64.


Una definición típica de PRIu16 sería "hu"por lo que la concatenación implícita de constantes de cadena ocurre en tiempo de compilación.

Para que su código sea completamente portátil, debe usar PRId32 y así sucesivamente para imprimir int32_ty "%d" o similar para imprimir int.

  • Lista completa de constantes de macro de formato: es.cppreference.com/w/cpp/types/integer

    – Masud Khaari

    14 mayo 2013 a las 10:45

  • Y, si usa C++ en Linux, asegúrese de #define __STDC_FORMAT_MACROS antes de incluir inttypes.h.

    – csl

    28 de noviembre de 2014 a las 8:50

  • PRId64 es una macro que se traduce internamente a "lld". Entonces, es tan bueno como escribir printf("%lld\n", t); Ver la descripción : qnx.com/developers/docs/6.5.0/…

    – Gaurav

    14 de agosto de 2015 a las 11:32


  • @Gaurav, eso es cierto en algunas plataformas, pero no en todas. En mi máquina AMD64 Linux, por ejemplo, PRId64 se define como ld. La portabilidad es la razón de la macro.

    – Ethan T.

    28 de junio de 2016 a las 15:06

  • Creo que con un poco de esfuerzo extra podrían haberlo hecho aún más desagradable.

    – Pavel P.

    27/10/2017 a las 23:35

avatar de usuario de pmg
pmg

La forma C99 es

#include <inttypes.h>
int64_t my_int = 999999999999999999;
printf("%" PRId64 "\n", my_int);

¡O podrías lanzar!

printf("%ld", (long)my_int);
printf("%lld", (long long)my_int); /* C89 didn't define `long long` */
printf("%f", (double)my_int);

Si está atascado con una implementación C89 (especialmente Visual Studio), quizás pueda usar una fuente abierta <inttypes.h> (y <stdint.h>): http://code.google.com/p/msinttypes/

  • Cuando uso msinttypes desde el enlace code.google.com, necesito definir __STDC_FORMAT_MACROS. Consulte stackoverflow.com/questions/8132399/how-to-printf-uint64-t.

    – ariscris

    28 mayo 2014 a las 16:49

  • Gracias por el aviso, @ariscris. Sin embargo, parece que la macro solo se requiere para C ++. Las definiciones en el código vinculado están dentro de un #if !defined(__cplusplus) || defined(__STDC_FORMAT_MACROS)

    – pmg

    28 mayo 2014 a las 17:08


avatar de usuario de pjhsea
pjhsea

Con C99 el %j El modificador de longitud también se puede usar con la familia de funciones printf para imprimir valores de tipo int64_t y uint64_t:

#include <stdio.h>
#include <stdint.h>

int main(int argc, char *argv[])
{
    int64_t  a = 1LL << 63;
    uint64_t b = 1ULL << 63;

    printf("a=%jd (0x%jx)\n", a, a);
    printf("b=%ju (0x%jx)\n", b, b);

    return 0;
}

Compilando este código con gcc -Wall -pedantic -std=c99 no produce advertencias y el programa imprime el resultado esperado:

a=-9223372036854775808 (0x8000000000000000)
b=9223372036854775808 (0x8000000000000000)

esto es de acuerdo a printf(3) en mi sistema Linux (la página de manual dice específicamente que j se utiliza para indicar una conversión a un intmax_t o uintmax_t; en mi stdint.h, ambos int64_t y intmax_t están tipificados exactamente de la misma manera, y de manera similar para uint64_t). No estoy seguro de si esto es perfectamente portátil a otros sistemas.

  • Si %jd imprime un intmax_tla invocación correcta sería printf("a=%jd (0x%jx)", (intmax_t) a, (intmax_t) a). No hay garantía de que int64_t y intmax_t son del mismo tipo, y si no lo son, el comportamiento es indefinido.

    – usuario4815162342

    25 de abril de 2013 a las 17:56

  • Puede usar de forma portátil %jd imprimir int64_t valores si los convierte explícitamente en intmax_t antes de pasarlos a printf: printf("a=%jd\n", (intmax_t)a). Esto evita la fealdad (en mi humilde opinión) de la <inttypes.h> macros Por supuesto, esto supone que su implementación admite %jd, int64_ty intmax_ttodos los cuales fueron agregados por C99.

    –Keith Thompson

    12 de agosto de 2013 a las 19:03

  • @KeithThompson ‘Fealdad’ lo está poniendo demasiado, demasiado amablemente amigo. Es absolutamente horrible. es espantoso. Es nauseabundo. Es vergonzoso es lo que es. O al menos deberían estar avergonzados, los que presentaron esto. Nunca he visto estas macros, pero haga lo que sugiere esta respuesta y los comentarios, incluidos los suyos.

    – Priftan

    3 de diciembre de 2019 a las 22:59

  • @Pryftan Yo no bastante encuéntrelos tan feos como usted, y no estoy del todo seguro de cómo podrían definirse de una manera menos fea sin cambios de idioma.

    –Keith Thompson

    4 de diciembre de 2019 a las 2:28

  • @KeithThompson Bueno, estoy agradecido de que al menos hayas puesto énfasis en la palabra ‘bastante’. Bueno, en realidad no importa. Sin embargo, no veo por qué las macros tienen que estar allí. Como dices, puedes transportarlo… Etc. Pero luego también encuentro que el aumento en la cantidad de palabras clave también se ha ido de las manos.

    – Priftan

    14 dic 2019 a las 20:46

Viniendo del mundo integrado, donde incluso uclibc no siempre está disponible, y código como

uint64_t myval = 0xdeadfacedeadbeef;
printf("%llx", myval);

está imprimiendo basura o no funciona en absoluto; siempre uso un pequeño ayudante, que me permite volcar correctamente uint64_t hex:

#include <stdlib.h>
#include <stdio.h>
#include <stdint.h>

char* ullx(uint64_t val)
{
    static char buf[34] = { [0 ... 33] = 0 };
    char* out = &buf[33];
    uint64_t hval = val;
    unsigned int hbase = 16;

    do {
        *out = "0123456789abcdef"[hval % hbase];
        --out;
        hval /= hbase;
    } while(hval);

    *out-- = 'x', *out="0";

    return out;
}

avatar de usuario de benlong
benlong

En el entorno de Windows, utilice

%I64d

en Linux, utilice

%lld

  • %lld es el formato para long long intcual es no necesariamente lo mismo que int64_t. <stdint.h> tiene una macro para el formato correcto para int64_t; ver la respuesta de ouah.

    –Keith Thompson

    12 de agosto de 2013 a las 19:05


  • @KeithThompson Sin embargo, desde long long es de al menos 64 bits, printf("%lld", (long long)x); debería funcionar, excepto quizás para -0x8000000000000000, que no podría representarse como un long long si ese tipo no está usando complemento a dos.

    – Pascal Cuoq

    12 de agosto de 2013 a las 20:54

  • @PascalCuoq: Sí, debería funcionar con el elenco (y la excepción que menciona es muy poco probable, se aplica solo a un sistema que admite el complemento a dos pero no lo usa para long long).

    –Keith Thompson

    12/08/2013 a las 21:10

Avatar de usuario de HarshaD
HarshaD

Me topé con esta pregunta cuando estaba buscando una forma de mostrar un número de 64 bits en hexadecimal:

Descubrí que puedes usar:

0x%016llx – al menos funciona con mi compilador (aarch64 GCC 7.3.0)

  • %lld es el formato para long long intcual es no necesariamente lo mismo que int64_t. <stdint.h> tiene una macro para el formato correcto para int64_t; ver la respuesta de ouah.

    –Keith Thompson

    12 de agosto de 2013 a las 19:05


  • @KeithThompson Sin embargo, desde long long es de al menos 64 bits, printf("%lld", (long long)x); debería funcionar, excepto quizás para -0x8000000000000000, que no podría representarse como un long long si ese tipo no está usando complemento a dos.

    – Pascal Cuoq

    12 de agosto de 2013 a las 20:54

  • @PascalCuoq: Sí, debería funcionar con el elenco (y la excepción que menciona es muy poco probable, se aplica solo a un sistema que admite el complemento a dos pero no lo usa para long long).

    –Keith Thompson

    12/08/2013 a las 21:10

//VC6.0 (386 y superior)

    __int64 my_qw_var = 0x1234567890abcdef;

    __int32 v_dw_h;
    __int32 v_dw_l;

    __asm
        {
            mov eax,[dword ptr my_qw_var + 4]   //dwh
            mov [dword ptr v_dw_h],eax

            mov eax,[dword ptr my_qw_var]   //dwl
            mov [dword ptr v_dw_l],eax

        }
        //Oops 0.8 format
    printf("val = 0x%0.8x%0.8x\n", (__int32)v_dw_h, (__int32)v_dw_l);

Saludos.

¿Ha sido útil esta solución?