Saya memiliki variabel tipe size_t
, dan saya ingin mencetaknya menggunakan printf()
. Penentu format apa yang saya gunakan untuk mencetaknya dengan mudah?
Di mesin 32-bit, %u
sepertinya benar. Saya kompilasi dengan g++ -g -W -Wall -Werror -ansi -pedantic
, dan tidak ada peringatan. Tetapi ketika saya mengkompilasi kode itu dalam mesin 64-bit, itu menghasilkan peringatan.
size_t x = <something>;
printf("size = %u\n", x);
warning: format '%u' expects type 'unsigned int',
but argument 2 has type 'long unsigned int'
Peringatan akan hilang, seperti yang diharapkan, jika saya mengubahnya menjadi %lu
.
Pertanyaannya adalah, bagaimana saya bisa menulis kode, sehingga mengkompilasi peringatan gratis pada mesin 32-dan 64-bit?
Sunting: Sebagai solusinya, saya kira satu jawaban mungkin untuk "melemparkan" variabel ke integer yang cukup besar, katakanlah unsigned long
, dan cetak menggunakan %lu
. Itu akan bekerja dalam kedua kasus. Saya mencari apakah ada ide lain.
unsigned long
adalah pilihan terbaik jika implementasi libc Anda tidak mendukungz
pengubah; standar C99 merekomendasikansize_t
untuk tidak memiliki peringkat konversi integer yang lebih besar daripadalong
, jadi Anda cukup amanJawaban:
Gunakan
z
pengubah:sumber
printf()
pengubah panjang konsep C ++ 0x dari 2009-11-09 (tabel 84 pada halaman 672)-pedantic
, Anda harus mendapatkan kompiler yang mendukung konsep C ++ 1x (sangat tidak mungkin), atau Anda harus memindahkan kode Anda ke file yang dikompilasi sebagai C99. Jika tidak, satu-satunya pilihan Anda adalah melemparkan variabel Anda keunsigned long long
dan gunakan%llu
untuk menjadi portabel secara maksimal.Sepertinya itu bervariasi tergantung pada kompiler yang Anda gunakan (blech):
%zu
(atau%zx
, atau%zd
yang menampilkannya seolah-olah ditandatangani, dll.)%Iu
(atau%Ix
, atau%Id
tapi sekali lagi itu masuk, dll.) - tetapi pada cl v19 (dalam Visual Studio 2015), Microsoft mendukung%zu
(lihat jawaban ini untuk komentar ini )... dan tentu saja, jika Anda menggunakan C ++, Anda dapat menggunakannya
cout
sebagai gantinya yang disarankan oleh AraK .sumber
z
juga didukung oleh newlib (yaitu cygwin)%zd
salah untuksize_t
; itu benar untuk jenis bertanda tangan yang sesuaisize_t
, tetapisize_t
itu sendiri adalah jenis yang tidak ditandatangani.%zu
juga (dan%zx
kalau-kalau mereka ingin hex). Cukup benar yang%zu
seharusnya menjadi yang pertama dalam daftar. Tetap.%zd
seharusnya tidak ada dalam daftar sama sekali. Saya tidak bisa memikirkan alasan untuk menggunakan%zd
daripada%zu
mencetaksize_t
nilai. Bahkan tidak valid (memiliki perilaku yang tidak terdefinisi) jika nilainya melebihiSIZE_MAX / 2
. (Untuk kelengkapan, Anda dapat menyebutkan%zo
untuk oktal.)ssize_t
jenis yang ditandatangani sesuaisize_t
, jadi tidak dijamin cocok"%zd"
. ( Mungkin pada sebagian besar implementasi.) Pubs.opengroup.org/onlinepubs/9699919799/basedefs/…Untuk C89, gunakan
%lu
dan berikan nilainya keunsigned long
:Untuk C99 dan yang lebih baru, gunakan
%zu
:sumber
unsigned long long
?uint64_t
dan kemudian menggunakanPRIu64
makro dari inttypes.h, yang berisi penentu format.Memperluas jawaban Adam Rosenfield untuk Windows.
Saya menguji kode ini dengan pratinjau VS2013 Update 4 dan VS2015:
VS2015 menghasilkan keluaran biner:
sedangkan yang dihasilkan oleh VS2013 mengatakan:
Catatan:
ssize_t
adalah ekstensi POSIX danSSIZE_T
hal serupa di Windows Data Type , maka saya menambahkan<BaseTsd.h>
referensi.Selain itu, kecuali untuk header C99 / C11 ikuti, semua header C99 tersedia dalam pratinjau VS2015:
Juga, C11
<uchar.h>
sekarang termasuk dalam pratinjau terbaru.Untuk detail lebih lanjut, lihat daftar lama dan baru ini untuk kesesuaian standar.
sumber
Bagi mereka yang berbicara tentang melakukan ini di C ++ yang tidak selalu mendukung ekstensi C99, maka saya sungguh-sungguh merekomendasikan boost :: format. Ini membuat pertanyaan ukuran size_t bisa diperdebatkan:
Karena Anda tidak memerlukan penentu ukuran dalam boost :: format, Anda bisa khawatir tentang bagaimana Anda ingin menampilkan nilainya.
sumber
%u
.sumber
printf
specifier secara spesifik. Saya kira mereka memiliki beberapa kendala tidak tercatat yang membuatstd::cout
masalah.printf
specifier."sumber
Seperti yang dikatakan AraK, antarmuka c ++ stream akan selalu bekerja dengan baik.
Jika Anda menginginkan C stdio, tidak ada jawaban portabel untuk ini untuk kasus "portabel" tertentu. Dan itu menjadi jelek karena seperti yang Anda lihat, memilih format bendera yang salah dapat menghasilkan peringatan kompiler atau memberikan output yang salah.
C99 mencoba menyelesaikan masalah ini dengan format inttypes.h seperti "%" PRIdMAX "\ n". Tetapi seperti halnya dengan "% zu", tidak semua orang mendukung c99 (seperti MSVS sebelum 2013). Ada file "msinttypes.h" yang beredar untuk menangani hal ini.
Jika Anda menggunakan tipe yang berbeda, bergantung pada flag, Anda mungkin mendapatkan peringatan kompilator untuk pemotongan atau perubahan tanda. Jika Anda memilih rute ini, pilih jenis ukuran tetap relevan yang lebih besar. Salah satu dari "% llu" panjang dan "llu" panjang yang tidak ditandatangani atau panjang harus bekerja, tetapi llu juga dapat memperlambat hal-hal di dunia 32bit sebagai terlalu besar. (Sunting - mac saya mengeluarkan peringatan dalam 64 bit untuk% llu tidak cocok dengan size_t, meskipun% lu,% llu, dan size_t semuanya berukuran sama. Dan% lu dan% llu bukan ukuran yang sama pada MSVS2012 saya. Jadi Anda mungkin perlu menggunakan + menggunakan format yang cocok.)
Untuk itu, Anda bisa menggunakan jenis ukuran tetap, seperti int64_t. Tapi tunggu! Sekarang kita kembali ke c99 / c ++ 11, dan MSVS yang lebih lama gagal lagi. Plus Anda juga memiliki gips (mis. Map.size () bukan tipe ukuran tetap)!
Anda bisa menggunakan header atau pustaka pihak ke-3 seperti boost. Jika Anda belum menggunakannya, Anda mungkin tidak ingin mengembang proyek Anda seperti itu. Jika Anda ingin menambahkan satu hanya untuk masalah ini, mengapa tidak menggunakan c ++ stream, atau kompilasi bersyarat?
Jadi Anda turun ke c ++ stream, kompilasi bersyarat, kerangka kerja pihak ke-3, atau semacam portable yang kebetulan bekerja untuk Anda.
sumber
Apakah ini akan memperingatkan Anda jika Anda meneruskan integer 32-bit yang tidak ditandatangani ke format% lu? Itu harus baik karena konversi didefinisikan dengan baik dan tidak kehilangan informasi apa pun.
Saya pernah mendengar bahwa beberapa platform mendefinisikan makro di
<inttypes.h>
mana Anda dapat memasukkan ke dalam format string literal tapi saya tidak melihat header itu di kompiler Windows C ++ saya, yang menyiratkan itu mungkin bukan cross-platform.sumber
%lu
, Anda harus memberikansize_t
nilainyaunsigned long
. Tidak ada konversi tersirat (selain promosi) untuk argumenprintf
.C99 mendefinisikan "% zd" dll untuk itu. (terima kasih kepada para komentator) Tidak ada specifier format portabel untuk itu di C ++ - Anda dapat menggunakan
%p
, yang kata woulkd dalam dua skenario ini, tetapi juga bukan pilihan portabel, dan memberikan nilai dalam hex.Atau, gunakan streaming (misalnya stringstream) atau pengganti printf yang aman seperti Boost Format . Saya mengerti bahwa saran ini hanya untuk penggunaan terbatas (dan memang membutuhkan C ++). (Kami telah menggunakan pendekatan serupa yang sesuai dengan kebutuhan kami saat menerapkan dukungan unicode.)
Masalah mendasar untuk C adalah bahwa printf menggunakan ellipsis tidak aman secara desain - ia perlu menentukan ukuran argumen tambahan dari argumen yang diketahui, sehingga tidak dapat diperbaiki untuk mendukung "apa pun yang Anda dapatkan". Jadi kecuali jika kompiler Anda menerapkan beberapa ekstensi milik, Anda tidak beruntung.
sumber
z
ukuran modidfier standar C, tetapi beberapa implementasi libc terjebak pada tahun 1990 karena berbagai alasan (misalnya Microsoft pada dasarnya ditinggalkan C mendukung C ++ dan - baru-baru - C #)%zd
salah, tidak ditandatangani sehingga seharusnya%zu
.Pada beberapa platform dan untuk beberapa jenis ada specifiers konversi printf tertentu yang tersedia, tetapi kadang-kadang kita harus beralih ke tipe yang lebih besar.
Saya telah mendokumentasikan masalah rumit ini di sini, dengan kode contoh: http://www.pixelbeat.org/programming/gcc/int_types/ dan memperbaruinya secara berkala dengan info tentang platform dan tipe baru.
sumber
jika Anda ingin mencetak nilai size_t sebagai string, Anda bisa melakukan ini:
hasilnya adalah:
nomor: 2337200120702199116
teks: Mari kita memancing bukannya duduk di atas tetapi !!
Sunting: membaca ulang pertanyaan karena suara turun saya perhatikan masalahnya bukan% llu atau% I64d tetapi tipe size_t pada mesin yang berbeda melihat pertanyaan ini https://stackoverflow.com/a/918909/1755797
http: // www. cplusplus.com/reference/cstdio/printf/
size_t adalah unsigned int pada mesin 32bit dan int longign unsigned pada 64bit
tapi% ll selalu mengharapkan int longign unsigned.
size_t bervariasi panjangnya pada sistem operasi yang berbeda sementara% llu adalah sama
sumber