Cómo imprimir un tipo int64_t en C

298

El estándar C99 tiene tipos enteros con un tamaño de bytes como int64_t. Estoy usando el siguiente código:

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

y recibo esta advertencia de compilación:

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

Lo intenté 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?

rtacconi
fuente

Respuestas:

420

Por int64_ttipo:

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

para uint64_ttipo:

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

También puede utilizar PRIx64para imprimir en hexadecimal.

cppreference.com tiene una lista completa de macros disponibles para todos los tipos, incluido 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 cadena constante ocurre en tiempo de compilación.

Para que su código sea totalmente portátil, debe usarlo PRId32y así sucesivamente para imprimir int32_t, y / "%d"o similar para imprimir int.

ouah
fuente
18
Lista completa de constantes de macro de formato: en.cppreference.com/w/cpp/types/integer
Massood Khaari
12
Y, si usa C ++ en Linux, asegúrese de #define __STDC_FORMAT_MACROSincluirlo antes inttypes.h.
csl
17
PRId64es una macro que se traduce internamente en "lld". Entonces, es tan bueno como escribir printf("%lld\n", t);Ver descripción: qnx.com/developers/docs/6.5.0/…
Gaurav
24
@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
10
Creo que con un esfuerzo extra podrían haberlo hecho aún más desagradable
Pavel P
65

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 de C89 (especialmente Visual Studio), tal vez pueda usar un código abierto <inttypes.h>(y <stdint.h>): http://code.google.com/p/msinttypes/

pmg
fuente
Cuando utilizo msinttypes desde el enlace code.google.com, necesito definir __STDC_FORMAT_MACROS. Ver stackoverflow.com/questions/8132399/how-to-printf-uint64-t .
ariscris
Gracias por el aviso, @ariscris. Sin embargo, parece que la macro solo es necesaria para C ++. Las definiciones en el código vinculado están dentro de un#if !defined(__cplusplus) || defined(__STDC_FORMAT_MACROS)
pmg
19

Con C99, el %jmodificador de longitud también se puede utilizar con la familia de funciones printf para imprimir valores de tipo int64_ty 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;
}

Compilar este código gcc -Wall -pedantic -std=c99no genera advertencias y el programa imprime el resultado esperado:

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

Esto está de acuerdo con printf(3)mi sistema Linux (la página del manual dice específicamente que jse usa para indicar una conversión a un intmax_to uintmax_t; en mi stdint.h, ambos int64_ty intmax_testán tipificados exactamente de la misma manera, y de manera similar para uint64_t). No estoy seguro de si esto es perfectamente portátil para otros sistemas.

pjhsea
fuente
12
Si %jdaparece una intmax_t, la invocación correcta sería printf("a=%jd (0x%jx)", (intmax_t) a, (intmax_t) a). No hay ninguna garantía de que int64_ty intmax_tson del mismo tipo, y si no es así, el comportamiento no está definido.
user4815162342
44
Se puede utilizar de forma portátil %jdpara imprimir int64_tlos valores si se les convierte explícitamente a intmax_tantes de pasarlos a printf: printf("a=%jd\n", (intmax_t)a). Esto evita la fealdad (en mi humilde opinión) de las <inttypes.h>macros. Por supuesto, esto supone que los soportes de aplicación %jd, int64_ty intmax_t, todos los cuales fueron añadidos por C99.
Keith Thompson el
2
@KeithThompson 'Ugliness' lo está poniendo muy, muy lejos, demasiado amable compañero. Es absolutamente horrible. Es espantoso. Es nauseabundo Es vergonzoso lo que es. O al menos deberían estar avergonzados, la suerte que introdujo esto. Nunca he visto estas macros, pero haga lo que sugieren esta respuesta y los comentarios, incluido el suyo.
Pryftan
@Pryftan no lo bastante encuentro bastante feo como lo hace - y no estoy del todo seguro de cómo podrían ser definidos de una manera menos feo y sin cambios en el lenguaje.
Keith Thompson, el
@KeithThompson Bueno, estoy agradecido de que al menos haya 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 transferir ... Etc. Pero luego también encuentro que el aumento en el número de palabras clave también se ha ido de las manos.
Pryftan
12

Procedente del mundo incrustado, donde incluso uclibc no siempre está disponible, y codifica 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 hexadecimal:

#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;
}
ataraxic
fuente
Si enfrenta este problema para una aplicación integrada, entonces esto es lo que está buscando. Esta solución funcionó para mí. Thnx @ataraxic.
Logan859
8

En el entorno de Windows, use

%I64d

en Linux, use

%lld
benlong
fuente
18
%lldes el formato para long long int, que no es necesariamente el mismo que int64_t. <stdint.h>tiene una macro para el formato correcto para int64_t; ver la respuesta de ouah .
Keith Thompson el
@KeithThompson Sin embargo, dado que long longes de al menos 64 bits, printf("%lld", (long long)x);debería funcionar, excepto quizás para -0x8000000000000000, que no podría ser representable como long longsi ese tipo no utilizara el complemento de dos.
Pascal Cuoq
@PascalCuoq: Sí, debería funcionar con el elenco (y la excepción que mencionas es muy poco probable, aplicando solo a un sistema que admite dos complementos pero no lo usa long long).
Keith Thompson
-3

//VC6.0 (386 y mejor)

    __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.

Daniel Ag
fuente