Bagaimana Anda memformat int panjang tak bertanda menggunakan printf?

379
#include <stdio.h>
int main() {
    unsigned long long int num = 285212672; //FYI: fits in 29 bits
    int normalInt = 5;
    printf("My number is %d bytes wide and its value is %ul. A normal number is %d.\n", sizeof(num), num, normalInt);
    return 0;
}

Keluaran:

My number is 8 bytes wide and its value is 285212672l. A normal number is 0.

Saya menganggap hasil tak terduga ini dari mencetak unsigned long long int. Bagaimana Anda printf()sebuah unsigned long long int?

andrewrk
sumber
2
Saya baru saja mengkompilasi kode Anda (dengan% llu) dengan gcc dan hasilnya adalah yang benar. Apakah Anda memberikan opsi kepada kompiler?
Juan
2
Perhatikan bahwa newlib samsung bada tampaknya tidak mendukung "% lld": developer.bada.com/forum/…
RzR
Saya akan menyarankan menggunakan stdint.h dan secara eksplisit tentang jumlah bit dalam variabel Anda. Kami masih dalam masa transisi antara arsitektur 32 dan 64 bit, dan "int panjang tanpa tanda" tidak berarti hal yang sama pada keduanya.
BD di Rivenhill

Jawaban:

483

Gunakan pengubah panjang-panjang ll (el-el) dengan konversi u (tidak ditandatangani). (Bekerja di windows, GNU).

printf("%llu", 285212672);
John Downey
sumber
11
Atau lebih tepatnya itu untuk GNU libc, dan tidak bekerja dengan Microsoft C runtime.
Mark Baker
168
Ini bukan Linux / UNIX, pengubah panjang "ll" ditambahkan ke Standard C di C99, jika tidak bekerja di "Microsoft C" maka itu karena mereka tidak memenuhi standar.
Robert Gamble
12
Bekerja untuk saya di VS2008. Selain itu, sejauh yang saya ingat MS C Compiler (ketika diatur untuk mengkompilasi lurus C) seharusnya sesuai dengan desain C90; C99 memperkenalkan beberapa hal yang tidak disukai semua orang.
ー パ ー フ ァ ミ コ ン
6
Satu hal yang perlu diingat di sini adalah bahwa jika Anda melewati beberapa long longargumen ke printfdan menggunakan format yang salah untuk salah satu dari mereka, katakan %dsaja %lld, maka bahkan argumen yang dicetak setelah yang salah dapat sepenuhnya mati (atau bahkan dapat menyebabkan printfcrash ). Pada dasarnya, argumen variabel diteruskan ke printf tanpa informasi jenis apa pun, jadi jika string format salah, hasilnya tidak dapat diprediksi.
dmitrii
1
Heard Herb Sutter mengatakan dalam sebuah wawancara bahwa pelanggan Microsoft tidak meminta C99 sehingga kompiler C murni mereka telah dibekukan di C90. Itu berlaku jika Anda mengkompilasi sebagai C. Jika Anda mengkompilasi sebagai C ++, seperti yang orang lain catat di atas, Anda seharusnya baik-baik saja.
ahcox
90

Anda mungkin ingin mencoba menggunakan perpustakaan inttypes.h yang memberikan jenis seperti int32_t, int64_t, uint64_tdll Anda kemudian dapat menggunakan macro nya seperti:

uint64_t x;
uint32_t y;

printf("x: %"PRId64", y: %"PRId32"\n", x, y);

Ini "dijamin" untuk tidak memberi Anda masalah yang sama dengan long, unsigned long longdll, karena Anda tidak perlu menebak berapa banyak bit di setiap tipe data.

Nathan Fellman
sumber
di mana ini PRId64, PRId32makro didefinisikan?
happy_marmoset
4
@happy_marmoset: mereka didefinisikan dalaminttypes.h
Nathan Fellman
4
Saya pikir Anda perlu PRIu64dan PRIu32untuk bilangan bulat bertanda tangan.
Lasse Kliemann
1
Apakah inttypes.hstandar? Bukan stdint.h?
MD XF
2
Perhatikan bahwa tipe lebar tepat ini adalah opsional , karena ada arsitektur di luar sana yang tidak memiliki tipe bilangan bulat dengan lebar persis itu. Hanya leastXdan fastXjenis (yang mungkin sebenarnya lebih luas dari yang ditunjukkan) yang wajib.
DevSolar
78

%d-> untuk int

%u-> untuk unsigned int

%ld-> untuk long intataulong

%lu-> untuk unsigned long intatau long unsigned intatauunsigned long

%lld-> untuk long long intataulong long

%llu-> untuk unsigned long long intatauunsigned long long

Shivam Chauhan
sumber
Apakah ada penentu format seperti jumlah digit untuk ditampilkan, pembenaran kiri atau kanan untuk% lld atau% llu?
Asam Padeh
40

Untuk jangka waktu lama (atau __int64) menggunakan MSVS, Anda harus menggunakan% I64d:

__int64 a;
time_t b;
...
fprintf(outFile,"%I64d,%I64d\n",a,b);    //I is capital i

sumber
37

Itu karena% llu tidak berfungsi dengan baik di bawah Windows dan% d tidak dapat menangani bilangan bulat 64 bit. Saya sarankan menggunakan PRIu64 sebagai gantinya dan Anda akan menemukan itu portabel untuk Linux juga.

Coba ini sebagai gantinya:

#include <stdio.h>
#include <inttypes.h>

int main() {
    unsigned long long int num = 285212672; //FYI: fits in 29 bits
    int normalInt = 5;
    /* NOTE: PRIu64 is a preprocessor macro and thus should go outside the quoted string. */
    printf("My number is %d bytes wide and its value is %" PRIu64 ". A normal number is %d.\n", sizeof(num), num, normalInt);
    return 0;
}

Keluaran

My number is 8 bytes wide and its value is 285212672. A normal number is 5.
Paul Hargreaves
sumber
+1 untuk referensi ke PRIu64, yang belum pernah saya lihat, tetapi ini tampaknya tidak portabel untuk Linux 64 bit (setidaknya) karena PRIu64 berkembang menjadi "lu" bukannya "llu".
BD di Rivenhill
8
Dan mengapa itu buruk? Panjang adalah nilai 64 bit pada 64 bit Linux, seperti pada setiap OS lain kecuali untuk Windows.
Ringding
@BDatRivenhill Linux / Unix menggunakan LP64 yang panjangnya 64 bit
phuclv
1
namun, untuk membuatnya lebih portabel, gunakan int64_tsebagai gantinya karena mungkin ada beberapa implementasi dengan panjang lebih besar dari panjang
phuclv
ini harus ke atas! - satu pembaruan kecil: kesalahan: akhiran tidak valid pada literal; C ++ 11 membutuhkan ruang antara literal dan pengidentifikasi [-Werverved-user-defined-literal]
tofutim
14

Di Linux itu %lludan di Windows itu%I64u

Meskipun saya telah menemukan itu tidak berfungsi di Windows 2000, tampaknya ada bug di sana!

Adam Pierce
sumber
dengan jendela, (atau setidaknya, dengan C compiler microsoft untuk windows) ada juga% I64d,% I32u, dan% I32d
JustJeff
1
Apa hubungannya dengan Windows 2000? C library adalah yang menangani printf.
CMircea
1
Apa yang saya amati. Saya menulis sebuah aplikasi yang menggunakan konstruksi ini dan bekerja dengan baik di WinXP tetapi meludahi sampah di Win2k. Mungkin itu ada hubungannya dengan system call yang dibuat oleh C library ke kernel, mungkin itu ada hubungannya dengan Unicode, siapa tahu. Saya ingat harus mengatasinya menggunakan _i64tot () atau sesuatu seperti itu.
Adam Pierce
7
Kedengarannya seperti MS menjalankan "kebebasan untuk berinovasi" lagi ... ;-)
Dronz
Masalah Win2k / Win9x kemungkinan karena unsigned long longdatatype yang relatif baru (pada saat itu, dengan standar C99) tetapi kompiler C (termasuk MinGW / GCC) memanfaatkan runtime Microsoft C lama yang hanya mendukung spesifikasi C89. Saya hanya memiliki akses ke dokumen API Windows yang sangat lama dan cukup baru. Jadi sulit untuk mengatakan dengan tepat kapan I64udukungan dijatuhkan. Tapi sepertinya era XP.
veganaiZe
8

Kompilasi sebagai x64 dengan VS2005:

% llu berfungsi dengan baik.

Sandy
sumber
3

Selain apa yang ditulis orang tahun lalu:

  • Anda mungkin mendapatkan kesalahan ini di gcc / mingw:

main.c:30:3: warning: unknown conversion type character 'l' in format [-Wformat=]

printf("%llu\n", k);

Maka versi mingw Anda tidak default ke c99. Menambahkan flag compiler ini: -std=c99.

Bernd Elkemann
sumber
3

Rupanya tidak ada yang datang dengan solusi multi-platform * selama lebih dari satu dekade sejak tahun 2008, jadi saya akan menambahkan milik saya 😛. Tolong unduh. (Bercanda. Saya tidak peduli.)

Larutan: lltoa()

Cara Penggunaan:

#include <stdlib.h> /* lltoa() */
// ...
char dummy[255];
printf("Over 4 bytes: %s\n", lltoa(5555555555, dummy, 10));
printf("Another one: %s\n", lltoa(15555555555, dummy, 10));

Contoh OP:

#include <stdio.h>
#include <stdlib.h> /* lltoa() */

int main() {
    unsigned long long int num = 285212672; // fits in 29 bits
    char dummy[255];
    int normalInt = 5;
    printf("My number is %d bytes wide and its value is %s. "
        "A normal number is %d.\n", 
        sizeof(num), lltoa(num, dummy, 10), normalInt);
    return 0;
}

Berbeda dengan %lldstring format cetak, yang ini berfungsi untuk saya di bawah 32-bit GCC pada Windows.

*) Yah, hampir multi-platform. Dalam MSVC, Anda tampaknya perlu _ui64toa()bukan lltoa().

7vujy0f0hy
sumber
1
Saya tidak punya lltoa.
Antti Haapala
1

Hal-hal yang tidak standar selalu aneh :)

untuk bagian panjang yang panjang di bawah GNU itu L, llatauq

dan di bawah windows saya percaya itu llhanya

percikan
sumber
1

Hex:

printf("64bit: %llp", 0xffffffffffffffff);

Keluaran:

64bit: FFFFFFFFFFFFFFFF
lama12345
sumber
Sangat bagus! saya bertanya-tanya bagaimana saya bisa mendapatkannya dalam representasi hex
0xAK
Tapi, hampir semua kompiler C ++ dan C memberikan peringatan: peringatan: penggunaan pengubah panjang 'll' dengan karakter tipe 'p' [-Wformat =]
Seshadri R
2
jawaban yang benar-benar rusak ini memiliki perilaku ganda yang tidak terdefinisi dan bahkan tidak mulai menjawab pertanyaan .
Antti Haapala
@AnttiHaapala Anda mengatakan jawaban ini benar-benar rusak dengan perilaku dua kali lipat, bisakah Anda menguraikan atau haruskah saya menghapusnya? Atau menjadikannya sebagai contoh buruk yang baik?
lama12345
0

Nah, salah satu caranya adalah mengkompilasinya sebagai x64 dengan VS2008

Ini berjalan seperti yang Anda harapkan:

int normalInt = 5; 
unsigned long long int num=285212672;
printf(
    "My number is %d bytes wide and its value is %ul. 
    A normal number is %d \n", 
    sizeof(num), 
    num, 
    normalInt);

Untuk kode 32 bit, kita perlu menggunakan specifier format __int64 yang benar% I64u. Jadi itu menjadi.

int normalInt = 5; 
unsigned __int64 num=285212672;
printf(
    "My number is %d bytes wide and its value is %I64u. 
    A normal number is %d", 
    sizeof(num),
    num, normalInt);

Kode ini berfungsi untuk kompiler VS 32 dan 64 bit.

vzczc
sumber
Coba nomor 64-bit yang sebenarnya, bukan '285212672' dan saya tidak percaya contoh pertama berjalan dengan benar, dikompilasi ke target apa pun.
dyasta