Jak wydrukować typ int64_t w C

298

Standard C99 ma typy liczb całkowitych o rozmiarze bajtów jak int64_t. Korzystam z następującego kodu:

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

i dostaję to ostrzeżenie kompilatora:

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

Próbowałem z:

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

Ale dostaję to samo ostrzeżenie. Korzystam z tego kompilatora:

~/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)

Jakiego formatu należy użyć, aby wydrukować zmienną my_int bez ostrzeżenia?

rtacconi
źródło

Odpowiedzi:

419

Dla int64_ttypu:

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

dla uint64_ttypu:

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

możesz także użyć PRIx64do drukowania w systemie szesnastkowym.

cppreference.com ma pełną listę dostępnych makr dla wszystkich typów, w tym intptr_t( PRIxPTR). Istnieją osobne makra dla scanf, takie jak SCNd64.


Typowa definicja PRIu16 byłaby "hu", więc domniemana ciągła konkatenacja ciągów zachodzi w czasie kompilacji.

Na Twój kod będzie w pełni przenośne, należy użyć PRId32i tak dalej do drukowania int32_ti "%d"czy podobna do drukowania int.

ouah
źródło
18
Pełna lista stałych makr formatowania: en.cppreference.com/w/cpp/types/integer
Massood Khaari
12
A jeśli używasz C ++ w systemie Linux, pamiętaj, aby #define __STDC_FORMAT_MACROSprzed włączeniem inttypes.h.
csl
17
PRId64to makro, które wewnętrznie się tłumaczy "lld". Jest więc tak dobry jak pisanie printf("%lld\n", t);Zobacz opis: qnx.com/developers/docs/6.5.0/…
Gaurav
24
@Gaurav, to prawda na niektórych platformach, ale nie na wszystkich. Na przykład na moim komputerze z amd64 Linux PRId64 jest zdefiniowany jako ld. Przenośność jest przyczyną tego makra.
Ethan T
10
Myślę, że przy dodatkowym wysiłku mogliby uczynić to jeszcze bardziej nieznośnym
Pavel P
65

Sposób C99 jest

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

Lub możesz rzucić!

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

Jeśli utkniesz z implementacją C89 (zwłaszcza Visual Studio), być może możesz użyć open source <inttypes.h>(i <stdint.h>): http://code.google.com/p/msinttypes/

pmg
źródło
Podczas korzystania z msinttypes z linku code.google.com muszę zdefiniować __STDC_FORMAT_MACROS. Zobacz stackoverflow.com/questions/8132399/how-to-printf-uint64-t .
ariscris
Dzięki za heads-up, @ariscris. Wygląda jednak na to, że makro jest wymagane tylko w C ++. Definicje w połączonym kodzie znajdują się w#if !defined(__cplusplus) || defined(__STDC_FORMAT_MACROS)
pmg
19

W C99 %jmodyfikator długości może być również używany z rodziną funkcji printf do drukowania wartości typu int64_ti 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;
}

Kompilowanie tego kodu bez gcc -Wall -pedantic -std=c99żadnych ostrzeżeń, a program wypisuje oczekiwane dane wyjściowe:

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

Jest to według printf(3)w moim systemie Linux (strona człowiek specjalnie mówi, że jjest używany do wskazywania konwersji na intmax_tlub uintmax_t, w moim stdint.h, zarówno int64_ti intmax_tsą typedef'd dokładnie w ten sam sposób i podobnie do uint64_t). Nie jestem pewien, czy jest to idealnie przenośne dla innych systemów.

pjhsea
źródło
12
Jeśli %jdprnts an intmax_t, poprawne wywołanie byłoby printf("a=%jd (0x%jx)", (intmax_t) a, (intmax_t) a). Nie ma gwarancji, że są int64_ti intmax_tsą tego samego typu, a jeśli nie są, zachowanie jest niezdefiniowane.
user4815162342
4
Można przenośnie użyć %jddo drukowania int64_twartości jeśli jawnie przekonwertować je intmax_tprzed przekazaniem ich do printf: printf("a=%jd\n", (intmax_t)a). Pozwala to uniknąć brzydoty <inttypes.h>makr (IMHO) . Oczywiście to zakłada się, że wspiera wdrożenie %jd, int64_toraz intmax_t, z których wszystkie zostały dodane przez C99.
Keith Thompson,
2
@KeithThompson „Brzydota” stawia ją o wiele za zdecydowanie zbyt uprzejmie. To absolutnie ohydne. To jest okropne. To mdli. To jest zawstydzające. A przynajmniej powinni się wstydzić, wielu, którzy to wprowadzili. Nigdy nie widziałem tych makr, ale rób to, co sugeruje ta odpowiedź i komentarze - w tym twoje.
Pryftan,
@Pryftan nie całkiem je znaleźć dość brzydka jak ty - a nie jestem wcale pewien, w jaki sposób mogą one być zdefiniowane w sposób mniej brzydki bez zmian językowych.
Keith Thompson,
@KeithThompson Cóż, jestem wdzięczny, że przynajmniej położyłeś nacisk na słowo „całkiem”. Właściwie to nie ma znaczenia. Nie rozumiem jednak, dlaczego makra muszą tam być. Jak mówisz, możesz przenosić ... Itd. Ale okazuje się, że wzrost liczby słów kluczowych również wymknął się spod kontroli.
Pryftan
12

Pochodzi z wbudowanego świata, w którym nawet uclibc nie zawsze jest dostępny i podobny do kodu

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

drukuje ci bzdury lub wcale nie działa - zawsze używam małego pomocnika, który pozwala mi poprawnie zrzucić szesnastkę uint64_t:

#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;
}
ataraksja
źródło
Jeśli masz do czynienia z tym problemem z aplikacją osadzoną, to właśnie tego szukasz. To rozwiązanie działało dla mnie. Thnx @ataraxic.
Logan859
8

W środowisku Windows użyj

%I64d

w systemie Linux użyj

%lld
benlong
źródło
18
%lldto format long long int, który nie koniecznie taka sama, jak int64_t. <stdint.h>ma makro odpowiedniego formatu int64_t; zobacz odpowiedź ouah .
Keith Thompson,
@KeithThompson Jednak, ponieważ long longjest co najmniej 64-bitowy, printf("%lld", (long long)x);powinien działać, z wyjątkiem być może -0x8000000000000000, co nie może być reprezentowane jako, long longjeśli ten typ nie używa uzupełnienia dwóch.
Pascal Cuoq,
@PascalCuoq: Tak, powinien działać z obsadą (a wspomniany wyjątek jest bardzo mało prawdopodobny, dotyczy tylko systemu, który obsługuje uzupełnienie dwóch, ale go nie używa long long).
Keith Thompson,
-3

//VC6.0 (386 i więcej)

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

Pozdrowienia.

Daniel Ag
źródło