int unsigned vs. size_t

492

Saya perhatikan bahwa kode C dan C ++ modern tampaknya menggunakan size_talih-alih int/ unsigned intcukup banyak di mana-mana - dari parameter untuk fungsi string C ke STL. Saya ingin tahu alasannya dan manfaatnya.

rampok
sumber

Jawaban:

388

The size_ttipe adalah tipe unsigned integer yang merupakan hasil dari sizeofoperator (dan offsetofoperator), sehingga dijamin akan cukup besar untuk menampung ukuran objek terbesar sistem Anda dapat menangani (misalnya, array statis 8Gb).

The size_tTipe mungkin lebih besar dari, sama dengan, atau lebih kecil dari unsigned int, dan compiler Anda mungkin membuat asumsi tentang hal itu untuk optimasi.

Anda dapat menemukan informasi yang lebih tepat dalam standar C99, bagian 7.17, konsep yang tersedia di Internet dalam format pdf , atau dalam standar C11, bagian 7.19, juga tersedia sebagai konsep pdf .

Remo.D
sumber
50
Nggak. Pikirkan x86-16 dengan model memori besar (tidak besar): Pointer jauh (32-bit), tetapi objek individual dibatasi hingga 64k (jadi size_t bisa 16-bit).
dan04
8
"ukuran objek terbesar" bukanlah kata-kata yang buruk, tetapi benar-benar benar. Keenam objek bisa jauh lebih terbatas daripada ruang alamat.
gnasher729
3
"Kompiler Anda mungkin membuat asumsi tentang hal itu": Saya berharap kompiler mengetahui kisaran nilai yang tepat yang size_tdapat mewakili! Jika tidak, siapa yang mau?
Marc van Leeuwen
4
@ Markc: Saya pikir intinya lebih bahwa kompiler mungkin dapat melakukan sesuatu dengan pengetahuan itu.
8
Saya hanya berharap tipe yang semakin populer ini tidak memerlukan dimasukkannya file header.
user2023370
74

Singkatnya, size_ttidak pernah negatif, dan ini memaksimalkan kinerja karena itu diketikkan akan menjadi tipe integer tak bertanda yang cukup besar - tetapi tidak terlalu besar - untuk mewakili ukuran objek terbesar yang mungkin ada pada platform target.

Ukuran tidak boleh negatif, dan memang size_tmerupakan tipe yang tidak ditandatangani. Selain itu, karena size_ttidak ditandatangani, Anda dapat menyimpan angka yang kira-kira dua kali lebih besar dari pada tipe bertanda tangan yang sesuai, karena kita dapat menggunakan bit tanda untuk mewakili besarnya, seperti semua bit lainnya dalam bilangan bulat yang tidak ditandai. Ketika kita memperoleh satu bit lagi, kita mengalikan rentang angka yang bisa kita wakili dengan faktor sekitar dua.

Jadi, Anda bertanya, mengapa tidak menggunakan saja unsigned int? Mungkin tidak dapat menampung angka yang cukup besar. Dalam implementasi di mana unsigned int32 bit, jumlah terbesar yang bisa diwakilinya adalah 4294967295. Beberapa prosesor, seperti IP16L32, dapat menyalin objek yang lebih besar dari 4294967295byte.

Jadi, Anda bertanya, mengapa tidak menggunakan unsigned long int? Ini memerlukan tol kinerja pada beberapa platform. Standar C mensyaratkan bahwa longmenempati setidaknya 32 bit. Platform IP16L32 mengimplementasikan setiap 32-bit selama sepasang kata 16-bit. Hampir semua operator 32-bit pada platform ini memerlukan dua instruksi, jika tidak lebih, karena mereka bekerja dengan 32 bit dalam dua potongan 16-bit. Misalnya, memindahkan panjang 32-bit biasanya membutuhkan dua instruksi mesin - satu untuk memindahkan setiap potongan 16-bit.

Menggunakan size_tmenghindari tol kinerja ini. Menurut artikel yang fantastis ini , "Jenis size_tadalah typedef yang merupakan alias untuk beberapa tipe integer yang tidak ditandatangani, biasanya unsigned intatau unsigned long, tetapi bahkan mungkin unsigned long long. Setiap implementasi Standar C seharusnya memilih integer yang tidak ditandai yang cukup besar - tetapi tidak lebih besar dari yang dibutuhkan - untuk mewakili ukuran objek terbesar yang mungkin ada di platform target. "

Rose Perrone
sumber
1
Maaf untuk mengomentari ini setelah sekian lama, tapi saya hanya harus mengkonfirmasi jumlah terbesar yang bisa dimiliki oleh seorang unsigned int - mungkin saya salah paham tentang terminologi Anda, tetapi saya berpikir bahwa jumlah terbesar yang bisa dimiliki oleh unsigned int adalah 4294967295, 65356 adalah maksimum dari short unsigned.
Mitch
Jika int unsigned Anda menempati 32 bit, maka ya, jumlah terbesar yang dapat ditampungnya adalah 2 ^ 32 - 1, yaitu 4294967295 (0xffffffff). Anda punya pertanyaan lain?
Rose Perrone
3
@Mitch: Nilai terbesar yang dapat direpresentasikan dalam unsigned intkaleng dan bervariasi dari satu sistem ke sistem lainnya. Ini diperlukan untuk menjadi setidaknya 65536 , tapi itu biasa 4294967295dan bisa menjadi 18446744073709551615(2 ** 64-1) pada beberapa sistem.
Keith Thompson
1
Nilai terbesar yang dapat mengandung int unsigned 16 bit adalah 65535, bukan 65536. Perbedaan kecil namun penting dengan 65536 adalah sama dengan 0 dalam int unsigned 16 bit.
Sie Raybould
1
@ gnasher729: Apakah Anda yakin tentang standar C ++? Setelah mencari selama beberapa waktu saya mendapat kesan bahwa mereka hanya menghapus semua jaminan absolut tentang rentang bilangan bulat (tidak termasuk unsigned char). Standar ini tampaknya tidak mengandung string '65535' atau '65536' di mana saja, dan '+32767' hanya terjadi (1.9: 9) dalam catatan sebagai kemungkinan integer terbesar yang dapat diwakili dalam int; tidak ada jaminan yang diberikan bahkan yang INT_MAXtidak bisa lebih kecil dari itu!
Marc van Leeuwen
51

Tipe size_t adalah tipe yang dikembalikan oleh operator sizeof. Ini adalah integer tanpa tanda yang mampu mengekspresikan ukuran dalam byte dari berbagai memori yang didukung pada mesin host. Ini (biasanya) terkait dengan ptrdiff_t dalam ptrdiff_t adalah nilai integer yang ditandatangani sehingga sizeof (ptrdiff_t) dan sizeof (size_t) sama.

Saat menulis kode C Anda harus selalu menggunakan size_t setiap kali berurusan dengan rentang memori.

Tipe int di sisi lain pada dasarnya didefinisikan sebagai ukuran nilai integer (ditandatangani) yang dapat digunakan oleh mesin host untuk melakukan aritmatika integer paling efisien. Sebagai contoh, pada banyak komputer jenis PC yang lebih lama, sizeof nilai (size_t) akan menjadi 4 (byte) tetapi sizeof (int) akan menjadi 2 (byte). Aritmatika 16 bit lebih cepat daripada aritmatika 32 bit, meskipun CPU dapat menangani ruang memori (logis) hingga 4 GiB.

Gunakan tipe int hanya ketika Anda peduli efisiensi karena ketepatan sebenarnya sangat bergantung pada opsi kompiler dan arsitektur mesin. Secara khusus standar C menentukan invarian berikut: sizeof (char) <= sizeof (pendek) <= sizeof (int) <= sizeof (panjang) tidak menempatkan batasan lain pada representasi aktual dari presisi yang tersedia untuk programmer untuk masing-masing tipe primitif ini.

Catatan: Ini BUKAN sama dengan di Jawa (yang sebenarnya menentukan presisi bit untuk masing-masing tipe 'char', 'byte', 'short', 'int' dan 'long').

Kevin S.
sumber
definisi de facto dari int adalah 16 bit pada 16 mesin dan 32 bit pada apa pun yang lebih besar. Terlalu banyak kode yang ditulis yang menganggap bahwa int adalah 32 bit lebar, untuk mengubahnya sekarang dan sebagai hasilnya orang harus selalu menggunakan size_t atau {, u} int {8,16,32,64} _t jika mereka menginginkan sesuatu yang spesifik - - sebagai tindakan pencegahan, orang harus selalu menggunakan ini, bukan tipe integer integral.
jelas
3
"Ini adalah integer tanpa tanda yang mampu mengekspresikan ukuran dalam byte dari berbagai memori yang didukung pada mesin host." -> No. size_tmampu mewakili ukuran objek tunggal (mis: angka, array, struktur). Seluruh rentang memori dapat melebihisize_t
chux - Reinstate Monica
"Saat menulis kode C Anda harus selalu menggunakan size_t setiap kali berurusan dengan rentang memori." - Itu menyiratkan bahwa setiap indeks untuk setiap array harus size_t- Saya harap Anda tidak bermaksud demikian. Sebagian besar waktu kita tidak berurusan dengan array di mana kardinalitas ruang alamat + portabilitas bahkan penting. Dalam kasus ini, Anda akan mengambil size_t. Dalam setiap kasus lain Anda mengambil indeks dari bilangan bulat (masuk). Karena kebingungan (yang datang tanpa peringatan) yang timbul dari perilaku arus bawah yang tidak terduga dari orang-orang yang tidak diundang lebih umum dan lebih buruk daripada masalah portabilitas yang mungkin timbul dalam kasus-kasus lain.
johannes_lalala
23

Ketik size_t harus cukup besar untuk menyimpan ukuran objek apa pun yang mungkin. Int unsigned tidak harus memenuhi kondisi itu.

Misalnya dalam sistem 64 bit int dan unsigned int mungkin lebar 32 bit, tetapi size_t harus cukup besar untuk menyimpan angka lebih besar dari 4G

Maciej Hehl
sumber
38
"objek" adalah bahasa yang digunakan oleh standar.
R .. GitHub BERHENTI MEMBANTU ICE
2
Saya pikir size_thanya harus sebesar itu jika kompiler dapat menerima tipe X sehingga sizeof (X) akan menghasilkan nilai yang lebih besar dari 4G. Sebagian besar penyusun akan menolak mis typedef unsigned char foo[1000000000000LL][1000000000000LL], dan bahkan foo[65536][65536];dapat ditolak secara sah jika melebihi batas yang ditentukan oleh implementasi yang terdokumentasi.
supercat
1
@MattJoiner: Kata-katanya baik-baik saja. "Objek" tidak samar-samar sama sekali, melainkan didefinisikan sebagai "wilayah penyimpanan".
Lightness Races dalam Orbit
4

Kutipan ini dari manual glibc 0.02 mungkin juga relevan ketika meneliti topik:

Ada potensi masalah dengan tipe size_t dan versi GCC sebelum rilis 2.4. ANSI C mengharuskan size_t selalu menjadi tipe yang tidak ditandai. Untuk kompatibilitas dengan file header sistem yang ada, GCC mendefinisikan size_t di stddef.h' to be whatever type the system'ssys / types.h 'mendefinisikannya menjadi. Sebagian besar sistem Unix yang mendefinisikan size_t di `sys / types.h ', mendefinisikannya sebagai tipe yang ditandatangani. Beberapa kode di pustaka tergantung pada size_t menjadi tipe yang tidak ditandatangani, dan tidak akan berfungsi dengan benar jika ditandatangani.

Kode pustaka GNU C yang mengharapkan size_t tidak ditandatangani adalah benar. Definisi size_t sebagai tipe yang ditandatangani salah. Kami berencana bahwa dalam versi 2.4, GCC akan selalu mendefinisikan size_t sebagai tipe yang tidak ditandatangani, dan fixincludes' script will massage the system'ssys / types.h 'agar tidak bertentangan dengan ini.

Sementara itu, kami mengatasi masalah ini dengan memberi tahu GCC secara eksplisit untuk menggunakan tipe yang tidak ditandatangani untuk size_t saat mengkompilasi pustaka GNU C. `configure 'akan secara otomatis mendeteksi tipe apa yang digunakan GCC untuk mengatur size_t untuk menimpanya jika perlu.

Graeme Burke
sumber
3

Jika kompiler saya disetel ke 32 bit, size_ttidak lain adalah typedef untuk unsigned int. Jika kompiler saya disetel ke 64 bit, size_ttidak lain adalah typedef untuk unsigned long long.

Ikan zebra
sumber
1
Dapat didefinisikan sebagai unsigned longuntuk kedua kasus pada beberapa OS.
StaceyGirl
-4

size_t adalah ukuran pointer.

Jadi dalam 32 bit atau model ILP32 (integer, panjang, pointer) umum size_t adalah 32 bit. dan dalam 64 bit atau model LP_t LP64 (panjang, pointer) umum adalah 64 bit (bilangan bulat masih 32 bit).

Ada beberapa model lain tetapi ini adalah model yang digunakan g ++ (setidaknya secara default)


sumber
15
size_tbelum tentu ukurannya sama dengan pointer, meskipun biasanya demikian. Pointer harus dapat menunjuk ke lokasi mana pun dalam memori; size_thanya harus cukup besar untuk mewakili ukuran objek tunggal terbesar.
Keith Thompson