Bagaimana cara saya mencetak jenis seperti off_t dan size_t?

148

Saya mencoba untuk mencetak jenis suka off_tdan size_t. Apa placeholder yang benar untuk printf() itu portabel ?

Atau adakah cara yang sama sekali berbeda untuk mencetak variabel-variabel itu?

Georg Schölly
sumber
2
@devin: Saya percaya saya telah menemukan bahwa jenis saat menggunakan fopen, fseek, dll di Mac OS X. off_tdigunakan untuk offset.
Georg Schölly

Jawaban:

112

Anda dapat menggunakan zuntuk size_t dan tuntuk ptrdiff_t seperti di

printf("%zu %td", size, ptrdiff);

Tetapi halaman buku saya mengatakan beberapa perpustakaan yang lebih tua menggunakan karakter yang berbeda dari zdan tidak mendukungnya. Namun demikian, itu standar (dengan standar C99). Bagi mereka intmax_tdan int8_tdari stdint.hdan seterusnya, ada makro yang dapat Anda gunakan, seperti jawaban lain yang dikatakan:

printf("value: %" PRId32, some_int32_t);
printf("value: %" PRIu16, some_uint16_t);

Mereka terdaftar di halaman manual inttypes.h.

Secara pribadi, saya hanya akan memberikan nilai unsigned longatau longmenyukai jawaban yang direkomendasikan. Jika Anda menggunakan C99, maka Anda dapat (dan harus, tentu saja) cor untuk unsigned long longatau long longdan menggunakan %lluatau %lldformat masing-masing.

Johannes Schaub - litb
sumber
2
off_t sebenarnya sudah lama ditandatangani di sistem saya.
Georg Schölly
2
Saya pikir halaman manual mencegah penggunaan Z (huruf besar) yang digunakan oleh libc5. Tampaknya tidak membuat z (huruf kecil) kecil.
Draemon
12
Menggunakan %zddengan size_tadalah perilaku undefined karena signedness mismatch (C99 7.19.6.1 # 9). Pasti begitu %zu.
Jens
7
Nah, bagaimana cara mencetak off_t?
JohnyTex
3
@ Jens Saya tidak melihat bagaimana %zddengan size_tperilaku yang tidak terdefinisi dari paragraf itu atau dari yang lain. Pada kenyataannya, definisi %zdalam # 7 secara eksplisit memungkinkan %ddengan size_tdan jenis bertanda tangan yang sesuai, dan §6.2.5 # 9 secara eksplisit memungkinkan penggunaan nilai-nilai dari jenis yang tidak ditandatangani di mana jenis yang ditandatangani diharapkan, asalkan nilainya adalah nilai nonnegatif yang valid dari tipe yang ditandatangani.
Chortos-2
108

Untuk mencetak off_t:

printf("%jd\n", (intmax_t)x);

Untuk mencetak size_t:

printf("%zu\n", x);

Untuk mencetak ssize_t:

printf("%zd\n", x);

Lihat 7.19.6.1/7 dalam standar C99, atau dokumentasi POSIX yang lebih mudah tentang kode pemformatan:

http://pubs.opengroup.org/onlinepubs/009695399/functions/fprintf.html

Jika implementasi Anda tidak mendukung kode pemformatan tersebut (misalnya karena Anda menggunakan C89), maka Anda memiliki sedikit masalah karena AFAIK tidak ada tipe integer di C89 yang memiliki kode pemformatan dan dijamin sebesar sebagai tipe ini. Jadi, Anda perlu melakukan sesuatu yang spesifik implementasi.

Misalnya jika kompiler Anda memiliki long longdan pustaka standar Anda mendukung %lld, Anda dapat dengan yakin mengharapkan yang akan menggantikannya intmax_t. Tetapi jika tidak, Anda harus kembali ke long, yang akan gagal pada beberapa implementasi lain karena terlalu kecil.

Steve Jessop
sumber
3
Sejauh ini, ini adalah jawaban yang lebih baik, saya akan lupa tentang menggunakan% zu untuk size_t yang tidak ditandatangani. Dan melakukan casting ke intmax_t adalah solusi yang bagus untuk apa pun off_t yang ada di platform apa pun.
Peter Cordes
2
POSIX tidak menjamin yang ssize_tmemiliki ukuran yang sama size_t, jadi kode yang benar-benar portabel harus mengubahnya menjadi intmax_tdan mencetak %jdseperti off_t.
nwellnhof
off_t dapat berukuran panjang hingga upto dan dapat bervariasi tergantung pada definisi ... Visual Studio memperingatkan dengan ini juga "peringatan C4477: '_snprintf_s': format string '% jd' memerlukan argumen tipe '__int64', tetapi argumen variadik 1 memiliki tipe 'off_t' "... Cara yang benar-benar portabel adalah printf ("% lld \ n ", (panjang) x);
ericcurtin
5

Untuk Microsoft, jawabannya berbeda. VS2013 sebagian besar memenuhi persyaratan C99 tetapi "[t] heh, j, z, dan t panjang prefix tidak didukung." Untuk size_t "yaitu, unsigned __int32 pada platform 32-bit, unsigned __int64 pada platform 64-bit" gunakan awalan I (modal mata) dengan specifier tipe o, u, x, atau X. Lihat spesifikasi ukuran VS2013

Sedangkan untuk off_t, ini didefinisikan sebagai panjang dalam VC \ include \ sys \ types.h.

NoBrassRing
sumber
Catatan jika off_tselalu longitu akan membuatnya 32-bit (bahkan 64-bit Windows menggunakan 32-bit untuk long).
sourcejedi
3

Versi C mana yang Anda gunakan?

Di C90, praktik standar adalah menggunakan untuk ditandatangani atau tidak ditandatangani lama, yang sesuai, dan cetak sesuai. Saya telah melihat% z untuk size_t, tetapi Harbison dan Steele tidak menyebutkannya di bawah printf (), dan dalam hal apa pun itu tidak akan membantu Anda dengan ptrdiff_t atau apa pun.

Di C99, berbagai jenis _t datang dengan makro printf mereka sendiri, jadi sesuatu seperti "Size is " FOO " bytes." saya tidak tahu detailnya, tapi itu bagian dari format numerik yang cukup besar termasuk file.

David Thornley
sumber
3

Anda ingin menggunakan makro pemformatan dari inttypes.h.

Lihat pertanyaan ini: String format platform silang untuk variabel tipe size_t?

Michael Burr
sumber
Dengan asumsi bahwa off_t adalah int, ukuran pointer ditandatangani (saya tidak tahu apa definisi yang tepat) seperti ptrdiff_t maka Anda akan menggunakan PRIdPTR atau PRIiPTR.
Michael Burr
11
The off_tjenis lebih besar dari pointer pada sistem 32-bit yang mendukung file besar (yang paling 32-bit sistem hari ini).
Dietrich Epp
1
@DietrichEpp: Sebenarnya, ini lebih buruk dari itu; banyak sistem 32-bit memiliki off_t dan off64_t, dan tergantung pada fitur makro off_t sebenarnya bisa berarti off64_t.
SamB
1

Melihat di man 3 printfLinux, OS X, dan OpenBSD semuanya menunjukkan dukungan %zuntuk size_tdan %tuntuk ptrdiff_t(untuk C99), tetapi tidak satupun yang menyebutkan off_t. Saran di alam liar biasanya menawarkan %ukonversi off_t, yang "cukup benar" sejauh yang saya tahu (keduanya unsigned intdan off_tbervariasi secara identik antara sistem 64-bit dan 32-bit).

dwc
sumber
1
Sistem saya (OS X) memiliki 32-bit unsigned intdan 64-bit off_t. Jadi para pemain akan menyebabkan data menjadi hilang.
Dietrich Epp
-3

Saya melihat posting ini setidaknya dua kali, karena jawaban yang diterima sulit untuk diingat bagi saya (saya jarang menggunakan zatau jmenandai dan mereka tampaknya bukan platform independen ).

The standar tidak pernah mengatakan secara jelas panjang data yang tepat dari size_t, jadi saya sarankan pertama Anda harus memeriksa panjang size_tpada platform Anda kemudian pilih salah satu dari mereka:

if sizeof(size_t) == 4 use PRIu32
if sizeof(size_t) == 8 use PRIu64

Dan saya sarankan menggunakan stdinttipe daripada tipe data mentah untuk konsistensi.

Elinx
sumber
1
Untuk C99 dan C11, standar secara eksplisit menyatakan bahwa %zudapat digunakan untuk mencetak size_tnilai. Satu harus pasti tidak resor untuk menggunakan uint32_t/ uint64_tformat yang specifier untuk mencetak size_t, karena tidak ada jaminan bahwa jenis-jenis yang kompatibel.
autis
-4

Seingat saya, satu-satunya cara portabel untuk melakukannya, adalah membuang hasilnya ke "unsigned long int" dan gunakan %lu.

printf("sizeof(int) = %lu", (unsigned long) sizeof(int));
James Curran
sumber
1
Harus "% lu", karena pengubah panjang harus datang sebelum konversi.
dwc
1
off_t misalnya sudah lama ditandatangani.
Georg Schölly
@ GeorgSchölly - Maka Anda telah menemukan teka-teki, karena long longtidak ada dalam standar C ++, dan dengan demikian bersifat non-portabel.
James Curran
-9

gunakan "% zo" untuk off_t. (oktal) atau "% zu" untuk desimal.

Shankar
sumber
Mengapa Anda ingin file offset dalam oktal?
poolie