Cara mencetak tipe int64_t dalam C

298

Standar C99 memiliki tipe integer dengan ukuran byte seperti int64_t. Saya menggunakan kode berikut:

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

dan saya mendapatkan peringatan kompiler ini:

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

Saya mencoba dengan:

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

Tapi saya mendapat peringatan yang sama. Saya menggunakan kompiler ini:

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

Format mana yang harus saya gunakan untuk mencetak variabel my_int tanpa peringatan?

rtacconi
sumber

Jawaban:

420

Untuk int64_tjenis:

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

untuk uint64_ttipe:

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

Anda juga dapat menggunakan PRIx64untuk mencetak dalam heksadesimal.

cppreference.com memiliki daftar lengkap makro yang tersedia untuk semua jenis termasuk intptr_t( PRIxPTR). Ada makro terpisah untuk scanf, seperti SCNd64.


Definisi tipikal PRIu16 adalah "hu", jadi rangkaian string-konstan implisit terjadi pada waktu kompilasi.

Agar kode Anda sepenuhnya portabel, Anda harus menggunakan PRId32dan sebagainya untuk mencetak int32_t, dan "%d"atau serupa untuk mencetak int.

ouah
sumber
18
Daftar lengkap konstanta pemformatan makro: en.cppreference.com/w/cpp/types/integer
Massood Khaari
12
Dan, jika menggunakan C ++ di Linux, pastikan untuk #define __STDC_FORMAT_MACROSmemasukkan sebelumnya inttypes.h.
csl
17
PRId64adalah makro yang diterjemahkan secara internal ke "lld". Jadi, sama baiknya dengan menulis. printf("%lld\n", t);Lihat deskripsi: qnx.com/developers/docs/6.5.0/…
Gaurav
24
@ Gaurav, itu benar pada beberapa platform, tetapi tidak pada semua. Pada mesin Linux amd64 saya, misalnya, PRId64 didefinisikan sebagai ld. Portabilitas adalah alasan untuk makro.
Ethan T
10
Saya pikir dengan upaya ekstra mereka bisa membuatnya lebih menjengkelkan
Pavel P
65

Cara C99 adalah

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

Atau Anda bisa melemparkan!

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

Jika Anda terjebak dengan implementasi C89 (terutama Visual Studio), Anda mungkin dapat menggunakan sumber terbuka <inttypes.h>(dan <stdint.h>): http://code.google.com/p/msinttypes/

pmg
sumber
Saat menggunakan msinttypes dari tautan code.google.com, saya perlu mendefinisikan __STDC_FORMAT_MACROS. Lihat stackoverflow.com/questions/8132399/how-to-printf-uint64-t .
ariscris
Terima kasih atas jawabannya, @ariscris. Tampaknya makro hanya diperlukan untuk C ++. Definisi dalam kode yang ditautkan ke dalam#if !defined(__cplusplus) || defined(__STDC_FORMAT_MACROS)
pmg
19

Dengan C99 %jpengubah panjang juga dapat digunakan dengan keluarga fungsi printf untuk mencetak nilai tipe int64_tdan 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;
}

Mengkompilasi kode ini dengan gcc -Wall -pedantic -std=c99tidak menghasilkan peringatan, dan program mencetak hasil yang diharapkan:

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

Ini sesuai dengan printf(3)pada sistem Linux saya (halaman manual secara khusus mengatakan yang jdigunakan untuk menunjukkan konversi ke intmax_tatau uintmax_t; di stdint.h saya, keduanya int64_tdan intmax_tdiketikkan dengan cara yang persis sama, dan sama untuk uint64_t). Saya tidak yakin apakah ini sangat portabel untuk sistem lain.

pjhsea
sumber
12
Jika %jdprnts an intmax_t, doa yang benar adalah printf("a=%jd (0x%jx)", (intmax_t) a, (intmax_t) a). Tidak ada jaminan bahwa int64_tdan intmax_tadalah tipe yang sama, dan jika tidak, perilaku tersebut tidak terdefinisi.
user4815162342
4
Anda portable dapat menggunakan %jduntuk mencetak int64_tnilai jika Anda secara eksplisit mengkonversikannya ke intmax_tsebelum melewati mereka untuk printf: printf("a=%jd\n", (intmax_t)a). Ini menghindari keburukan (IMHO) dari <inttypes.h>makro. Tentu saja ini mengasumsikan bahwa dukungan implementasi %jd, int64_tdan intmax_t, semua yang ditambahkan oleh C99.
Keith Thompson
2
@KeithThompson 'Keburukan' membuatnya jauh terlalu baik sobat. Benar-benar mengerikan. Ini mengerikan. Ini memuakkan. Ini memalukan. Atau setidaknya mereka harus malu, banyak yang memperkenalkan ini. Saya belum pernah melihat makro ini tetapi melakukan apa yang disarankan oleh jawaban ini dan komentar - termasuk Anda -.
Pryftan
@Pryftan Saya tidak cukup menemukan mereka cukup jelek seperti yang Anda lakukan - dan aku sama sekali tidak yakin bagaimana mereka dapat didefinisikan dengan cara yang lebih jelek tanpa perubahan bahasa.
Keith Thompson
@KeithThompson Yah saya berterima kasih setidaknya Anda memberi tekanan pada kata 'cukup'. Sebenarnya tidak masalah. Saya tidak melihat mengapa makro harus ada di sana. Seperti yang Anda katakan Anda dapat portable ... Dll. Tapi kemudian saya juga menemukan bahwa peningkatan jumlah kata kunci telah keluar dari tangan juga.
Pryftan
12

Berasal dari dunia tertanam, di mana bahkan uclibc tidak selalu tersedia, dan kode suka

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

sedang mencetak Anda omong kosong atau tidak bekerja sama sekali - saya selalu menggunakan pembantu kecil, yang memungkinkan saya untuk membuang dengan benar 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;
}
ataraxic
sumber
Jika Anda menghadapi masalah ini untuk aplikasi yang disematkan, maka inilah yang Anda cari. Solusi ini berhasil untuk saya. Thnx @ataraxic.
Logan859
8

Di lingkungan windows, gunakan

%I64d

di Linux, gunakan

%lld
Benlong
sumber
18
%lldadalah format untuk long long int, yang belum tentu sama dengan int64_t. <stdint.h>memiliki makro untuk format yang benar untuk int64_t; lihat jawaban ouah .
Keith Thompson
@KeithThompson Namun, karena long longsetidaknya 64-bit, printf("%lld", (long long)x);harus bekerja, kecuali mungkin untuk -0x800000000000000000, yang tidak dapat dianggap sebagai long longjika tipe itu tidak menggunakan komplemen dua.
Pascal Cuoq
@ PascalCuoq: Ya, itu harus bekerja dengan para pemain (dan pengecualian yang Anda sebutkan sangat tidak mungkin, hanya berlaku untuk sistem yang mendukung dua komplemen tetapi tidak menggunakannya untuk long long).
Keith Thompson
-3

//VC6.0 (386 & lebih baik)

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

Salam.

Daniel Ag
sumber