Como imprimir um tipo int64_t em C

298

O padrão C99 possui tipos inteiros com tamanho de bytes como int64_t. Estou usando o seguinte código:

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

e recebo este aviso do compilador:

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

Eu tentei com:

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

Mas eu recebo o mesmo aviso. Estou 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)

Qual formato devo usar para imprimir a variável my_int sem ter um aviso?

rtacconi
fonte

Respostas:

420

Para o int64_ttipo:

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

para o uint64_ttipo:

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

você também pode usar PRIx64para imprimir em hexadecimal.

cppreference.com tem uma lista completa de macros disponíveis para todos os tipos, incluindo intptr_t( PRIxPTR). Existem macros separadas para scanf, como SCNd64.


Uma definição típica de PRIu16 seria "hu", portanto, a concatenação implícita de constante de sequência acontece em tempo de compilação.

Para que seu código seja totalmente portátil, você deve usar PRId32e assim por diante para impressão int32_te "%d"similares ou para impressão int.

ouah
fonte
18
Lista completa de formatação constantes de macro: en.cppreference.com/w/cpp/types/integer
Massood Khaari
12
E, se estiver usando C ++ no Linux, certifique-se de #define __STDC_FORMAT_MACROSincluir antes inttypes.h.
CSL
17
PRId64é uma macro que se traduz internamente "lld". Assim, é tão bom quanto escrevendo printf("%lld\n", t);Veja a descrição: qnx.com/developers/docs/6.5.0/...
Gaurav
24
@ Gaurav, isso é verdade em algumas plataformas, mas não em todas. Na minha máquina Linux amd64, por exemplo, PRId64 é definido como ld. Portabilidade é o motivo da macro.
Ethan T
10
Eu acho que com algum esforço extra que poderia ter feito ainda mais detestável
Pavel P
65

O caminho C99 é

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

Ou você poderia lançar!

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

Se você está preso à implementação do C89 (principalmente o Visual Studio), pode usar um código aberto <inttypes.h>(e <stdint.h>): http://code.google.com/p/msinttypes/

pmg
fonte
Ao usar msinttypes no link code.google.com, preciso definir __STDC_FORMAT_MACROS. Consulte stackoverflow.com/questions/8132399/how-to-printf-uint64-t .
Ariscris 28/05
Obrigado pela atenção, @ariscris. Parece que a macro é necessária apenas para C ++. As definições no código vinculado a estão dentro de um#if !defined(__cplusplus) || defined(__STDC_FORMAT_MACROS)
pmg 28/05
19

Com C99, o %jmodificador de comprimento também pode ser usado com a família de funções printf para imprimir valores do tipo int64_te 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 esse código com gcc -Wall -pedantic -std=c99não produz avisos, e o programa imprime a saída esperada:

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

Isto é de acordo com printf(3) meu sistema Linux (a página de manual diz especificamente que jé usada para indicar uma conversão para um intmax_tou uintmax_t; no meu stdint.h, ambos int64_te intmax_tsão digitados exatamente da mesma maneira e da mesma forma para uint64_t). Não tenho certeza se isso é perfeitamente portátil para outros sistemas.

pjhsea
fonte
12
Se %jdprnts an intmax_t, a chamada correta seria printf("a=%jd (0x%jx)", (intmax_t) a, (intmax_t) a). Não há garantia de que int64_te intmax_tsejam do mesmo tipo e, se não forem, o comportamento será indefinido.
user4815162342
4
Você pode portably usar %jdpara imprimir int64_tvalores se você convertê-los explicitamente intmax_tantes de passá-los para printf: printf("a=%jd\n", (intmax_t)a). Isso evita a feiura (IMHO) das <inttypes.h>macros. Claro que isso pressupõe que os seus suportes de implementação %jd, int64_te intmax_t, todos os quais foram adicionados pelo C99.
21813 Keith Thompson
2
@KeithThompson 'Feiúra' está colocando isso longe demais, por favor, companheiro. É absolutamente hediondo. É horrível. É nauseante. É embaraçoso o que é. Ou pelo menos eles deveriam ter vergonha, o que introduziu isso. Eu nunca vi essas macros, mas faça o que essa resposta e os comentários - incluindo os seus - sugerem.
Pryftan
@Pryftan eu não bastante encontrá-los tão feia como você - e eu não tenho certeza de como eles poderiam ser definidos de uma forma menos feio, sem alterações de linguagem.
Keith Thompson
@KeithThompson Bem, eu sou grato por pelo menos enfatizar a palavra 'bastante'. Bem, na verdade não importa. Não vejo por que as macros precisam estar lá. Como você diz que pode ser portável ... Etc. Mas também acho que o aumento no número de palavras-chave também ficou fora de controle.
Pryftan
12

Vindo do mundo incorporado, onde nem o uclibc está sempre disponível, e codifica como

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

está imprimindo sua porcaria ou não está funcionando - eu sempre uso um pequeno auxiliar, que me permite despejar corretamente 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;
}
ataraxico
fonte
Se você está enfrentando esse problema para um aplicativo incorporado, é isso que você está procurando. Esta solução funcionou para mim. Thnx @ataraxic.
Logan859 26/02
8

No ambiente Windows, use

%I64d

no Linux, use

%lld
benlong
fonte
18
%lldé o formato para long long int, que não é necessariamente o mesmo que int64_t. <stdint.h>possui uma macro para o formato correto para int64_t; veja a resposta de ouah .
21813 Keith Thompson
@KeithThompson No entanto, como long longé pelo menos 64 bits, printf("%lld", (long long)x);deve funcionar, exceto talvez -0x8000000000000000, que não pode ser representável como long longse esse tipo não estivesse usando o complemento de dois.
Pascal Cuoq 12/08
@PascalCuoq: Sim, ele deve funcionar com o elenco (e a exceção mencionada é muito improvável, se aplicar apenas a um sistema que suporte o complemento de dois, mas não o use long long).
Keith Thompson
-3

//VC6.0 (386 e melhor)

    __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);

Saudações.

Daniel Ag
fonte