Dalam C ++, size_t
(atau, lebih tepatnya T::size_type
yang "biasanya" size_t
; yaitu, unsigned
tipe) digunakan sebagai nilai balik untuk size()
, argumen ke operator[]
, dll. (Lihat std::vector
, et. Al.)
Di sisi lain, bahasa .NET menggunakan int
(dan, opsional, long
) untuk tujuan yang sama; bahkan, bahasa yang sesuai dengan CLS tidak diperlukan untuk mendukung jenis yang tidak ditandatangani .
Mengingat bahwa .NET lebih baru daripada C ++, sesuatu memberi tahu saya bahwa mungkin ada masalah menggunakan unsigned int
bahkan untuk hal-hal yang "tidak mungkin" menjadi negatif seperti indeks atau panjang array. Apakah pendekatan C ++ "artefak historis" untuk kompatibilitas mundur? Atau adakah pertukaran desain nyata dan signifikan antara kedua pendekatan?
Mengapa ini penting? Nah ... apa yang harus saya gunakan untuk kelas multi-dimensi baru di C ++; size_t
atau int
?
struct Foo final // e.g., image, matrix, etc.
{
typedef int32_t /* or int64_t*/ dimension_type; // *OR* always "size_t" ?
typedef size_t size_type; // c.f., std::vector<>
dimension_type bar_; // maybe rows, or x
dimension_type baz_; // e.g., columns, or y
size_type size() const { ... } // STL-like interface
};
-1
dikembalikan dari fungsi yang mengembalikan indeks, untuk menunjukkan "tidak ditemukan" atau "di luar jangkauan." Itu juga dikembalikan dariCompare()
fungsi (implementasiIComparable
). Int 32 bit dianggap sebagai tipe ketikan untuk nomor umum, karena saya harap alasan yang jelas.Jawaban:
Iya. Untuk jenis aplikasi tertentu seperti pemrosesan gambar atau pemrosesan array, seringkali diperlukan untuk mengakses elemen relatif ke posisi saat ini:
Dalam jenis aplikasi ini, Anda tidak dapat melakukan pemeriksaan rentang dengan bilangan bulat tanpa tanda tanpa berpikir dengan hati-hati:
Alih-alih, Anda harus mengatur ulang ekspresi pemeriksaan rentang. Itulah perbedaan utama. Pemrogram juga harus mengingat aturan konversi bilangan bulat. Jika ragu, baca kembali http://en.cppreference.com/w/cpp/language/operator_arithmetic#Conversions
Banyak aplikasi tidak perlu menggunakan indeks array yang sangat besar, tetapi mereka perlu melakukan pemeriksaan jangkauan. Selanjutnya, banyak programmer yang tidak terlatih untuk melakukan senam penataan ulang ekspresi ini. Satu peluang yang terlewatkan membuka pintu bagi suatu eksploitasi.
C # memang dirancang untuk aplikasi-aplikasi yang tidak akan membutuhkan lebih dari 2 ^ 31 elemen per array. Misalnya, aplikasi spreadsheet tidak perlu berurusan dengan banyak baris, kolom, atau sel. C # berurusan dengan batas atas dengan memeriksa aritmatika opsional yang dapat diaktifkan untuk blok kode dengan kata kunci tanpa mengacaukan opsi kompiler. Untuk alasan ini, C # mendukung penggunaan bilangan bulat yang ditandatangani. Ketika keputusan ini dianggap sama sekali, itu masuk akal.
C ++ sangat berbeda, dan lebih sulit untuk mendapatkan kode yang benar.
Mengenai pentingnya praktis memungkinkan aritmatika yang ditandatangani untuk menghapus potensi pelanggaran "prinsip takjub", satu kasus yang dimaksud adalah OpenCV, yang menggunakan integer 32-bit yang ditandatangani untuk indeks elemen matriks, ukuran array, jumlah saluran piksel, dll. Gambar pemrosesan adalah contoh dari domain pemrograman yang banyak menggunakan indeks array relatif. Underflow integer yang tidak ditandatangani (hasil negatif yang dibungkus) akan sangat menyulitkan implementasi algoritma.
sumber
Jawaban ini benar-benar tergantung pada siapa yang akan menggunakan kode Anda, dan standar apa yang ingin mereka lihat.
size_t
adalah ukuran integer dengan tujuan:Jadi, setiap kali Anda ingin bekerja dengan ukuran objek dalam byte, Anda harus menggunakan
size_t
. Sekarang dalam banyak kasus, Anda tidak menggunakan dimensi / indeks ini untuk menghitung byte, tetapi kebanyakan pengembang memilih untuk menggunakannya disize_t
sana untuk konsistensi.Perhatikan bahwa Anda harus selalu menggunakan
size_t
jika kelas Anda dimaksudkan untuk memiliki tampilan dan nuansa kelas STL. Semua kelas STL dalam penggunaan spesifikasisize_t
. Adalah valid untuk compiler untuk mengetikkansize_t
menjadiunsigned int
, dan itu juga berlaku untuk itu diketikkan keunsigned long
. Jika Anda menggunakanint
ataulong
langsung, pada akhirnya Anda akan menemui kompiler di mana seseorang yang berpikir kelas Anda mengikuti gaya STL terjebak karena Anda tidak mengikuti standar.Adapun untuk menggunakan tipe yang ditandatangani, ada beberapa keuntungan:
int
, tetapi jauh lebih sulit untuk mengacaukan kodenyaunsigned int
.int32_t
danuint32_t
). Ini dapat membuat interoperabilitas API lebih sederhanaKerugian besar dari tipe yang ditandatangani adalah yang jelas: Anda kehilangan setengah dari domain Anda. Nomor yang ditandatangani tidak dapat dihitung setinggi nomor yang tidak ditandatangani. Ketika C / C ++ muncul, ini sangat penting. Salah satu yang diperlukan untuk dapat mengatasi kemampuan penuh prosesor, dan untuk itu Anda perlu menggunakan nomor yang tidak ditandatangani.
Untuk jenis-jenis aplikasi .NET yang ditargetkan, tidak ada kebutuhan yang kuat untuk indeks tak bertanda domain lengkap. Banyak tujuan untuk angka-angka seperti itu hanya tidak valid dalam bahasa yang dikelola (kumpulan memori muncul di pikiran). Juga, ketika. NET keluar, komputer 64-bit jelas masa depan. Kami masih jauh dari membutuhkan seluruh bilangan bulat 64-bit, jadi mengorbankan satu bit tidak sesakit sebelumnya. Jika Anda benar-benar membutuhkan 4 miliar indeks, Anda cukup beralih menggunakan integer 64-bit. Paling buruk, Anda menjalankannya pada mesin 32 bit dan agak lambat.
Saya melihat perdagangan sebagai salah satu kenyamanan. Jika Anda memiliki kekuatan komputasi yang cukup sehingga Anda tidak keberatan menyia-nyiakan sedikit tipe indeks yang tidak akan pernah Anda gunakan, maka cukup nyaman untuk mengetik
int
ataulong
berjalan menjauh darinya. Jika Anda benar-benar menginginkan yang terakhir, maka Anda mungkin harus memerhatikan ketandatanganan nomor Anda.sumber
size()
adalahreturn bar_ * baz_;
; bukankah itu sekarang membuat masalah potensial dengan integer overflow (membungkus) yang saya tidak akan miliki jika saya tidak menggunakansize_t
?bar_ * baz_
dapat meluap integer yang ditandatangani tetapi bukan integer yang tidak ditandatangani. Membatasi diri kita sendiri ke C ++, perlu dicatat bahwa overflow unsigned didefinisikan dalam spesifikasi, tetapi overflow yang ditandatangani adalah perilaku yang tidak terdefinisi, jadi jika modulo aritmatika bilangan bulat yang tidak diinginkan diinginkan, pasti gunakan, karena sebenarnya didefinisikan!size()
meluap menandatangani perkalian, Anda berada di tanah bahasa UB. (dan dalamfwrapv
mode, lihat berikutnya :) Ketika kemudian , dengan sedikit lebih sedikit, itu meluap- lipat dari multiplikasi yang tidak ditandatangani , Anda berada di tanah kode-pengguna-bug - Anda akan mengembalikan ukuran palsu. Jadi saya tidak berpikir unsigned membeli banyak di sini.Saya pikir jawaban rwong di atas sudah sangat baik menyoroti masalah.
Saya akan menambahkan 002 saya:
size_t
, yaitu ukuran yang ...... hanya diperlukan untuk indeks rentang saat
sizeof(type)==1
, yaitu, jika Anda berurusan denganchar
tipe byte ( ). (Tapi, kami perhatikan, ini bisa lebih kecil dari tipe ptr :xxx::size_type
dapat digunakan dalam 99,9% kasus bahkan jika itu adalah tipe ukuran yang ditandatangani. (bandingkanssize_t
)std::vector
dan teman-teman memilihsize_t
, tipe yang tidak ditandatangani , untuk ukuran dan pengindeksan dianggap oleh beberapa orang sebagai cacat desain. Saya setuju. (Serius, ambil 5 menit dan saksikan pembicaraan kilat CppCon 2016: Jon Kalb “unsigned: A Guideline for Better Code" .)size_t
agar konsisten dengan Perpustakaan Standar, atau gunakan ( bertanda tangan )intptr_t
ataussize_t
untuk penghitungan pengindeksan yang mudah bug dan lebih mudah.intptr_t
jika Anda ingin masuk, dan ingin ukuran kata mesin, atau gunakanssize_t
.Untuk langsung menjawab pertanyaan, itu tidak sepenuhnya merupakan "artefak sejarah", karena masalah teoretis tentang perlunya mengatasi lebih dari separuh ("pengindeksan", atau) ruang alamat harus , aehm, ditangani entah bagaimana dalam bahasa tingkat rendah seperti C ++.
Kalau dipikir-pikir, saya, secara pribadi , berpikir, ini adalah cacat desain yang digunakan oleh Perpustakaan Standar tanpa tanda di
size_t
semua tempat bahkan di mana itu tidak mewakili ukuran memori mentah, tetapi kapasitas data yang diketik, seperti untuk koleksi:Saya akan mengulangi saran Jon di sini:
(* 1) yaitu unsigned == bitmask, jangan pernah menghitungnya (di sini ada pengecualian pertama - Anda mungkin perlu penghitung yang membungkus - ini harus jenis yang tidak ditandatangani.)
(* 2) jumlah berarti sesuatu yang Anda hitung dan / atau hitung.
sumber
ssize_t
, yang didefinisikan sebagai liontin yang ditandatangani,size_t
bukanintptr_t
, yang dapat menyimpan penunjuk (bukan anggota) dan karenanya mungkin lebih besar?size_t
definisi yang sedikit kacau. Lihat size_t vs. intptr dan en.cppreference.com/w/cpp/types/size_t Mempelajari sesuatu yang baru hari ini. :-) Saya pikir sisa argumen berdiri, saya akan melihat apakah saya dapat memperbaiki jenis yang digunakan.Saya hanya akan menambahkan bahwa untuk alasan kinerja saya biasanya menggunakan size_t, untuk memastikan bahwa kesalahan perhitungan menyebabkan underflow yang berarti pemeriksaan rentang (di bawah nol dan di atas ukuran ()) dapat dikurangi menjadi satu:
menggunakan int yang ditandatangani:
menggunakan int unsigned:
sumber