Ketika saya belajar bahasa C ++ untuk pertama kalinya saya belajar bahwa selain int, float dll, versi yang lebih kecil atau lebih besar dari tipe data ini ada dalam bahasa tersebut. Misalnya saya bisa memanggil variabel x
int x;
or
short int x;
Perbedaan utama adalah bahwa int pendek mengambil 2 byte memori sedangkan int mengambil 4 byte, dan int pendek memiliki nilai lebih rendah, tetapi kita juga bisa menyebutnya ini untuk membuatnya lebih kecil:
int x;
short int x;
unsigned short int x;
yang bahkan lebih ketat.
Pertanyaan saya di sini adalah apakah itu praktik yang baik untuk menggunakan tipe data terpisah sesuai dengan nilai apa yang variabel Anda ambil dalam program. Apakah ide yang baik untuk selalu mendeklarasikan variabel sesuai dengan tipe data ini?
c++
data-structures
Bugster
sumber
sumber
unsigned
entah bagaimana membuat integer menempati lebih sedikit ruang, yang tentu saja salah. Ini akan memiliki jumlah nilai representatif diskrit yang sama (memberi atau menerima 1 tergantung pada bagaimana tanda diwakili) tetapi hanya bergeser secara eksklusif ke positif.Jawaban:
Sebagian besar waktu biaya ruang diabaikan dan Anda tidak perlu khawatir tentang hal itu, namun Anda harus khawatir tentang informasi tambahan yang Anda berikan dengan mendeklarasikan jenis. Misalnya, jika Anda:
Anda memberikan informasi yang berguna kepada pengembang lain: gaji tidak boleh negatif.
Perbedaan antara pendek, int, panjang jarang akan menyebabkan masalah ruang dalam aplikasi Anda. Anda cenderung secara tidak sengaja membuat asumsi keliru bahwa suatu angka akan selalu cocok dengan beberapa tipe data. Mungkin lebih aman untuk selalu menggunakan int kecuali Anda 100% yakin angka Anda akan selalu sangat kecil. Meski begitu, tidak mungkin untuk menghemat jumlah ruang yang terlihat.
sumber
unsigned
dalam kasus ini adalah ide yang buruk: tidak hanya gaji tidak boleh negatif, tetapi perbedaan antara dua gaji juga tidak boleh negatif. (Secara umum, menggunakan unsigned untuk apa pun kecuali sedikit-twiddling dan memiliki perilaku yang didefinisikan pada overflow adalah ide yang buruk.)OP mengatakan apa-apa tentang jenis sistem mereka menulis program untuk, tetapi saya menganggap OP memikirkan PC khas dengan memori GB sejak C ++ disebutkan. Seperti yang dikatakan salah satu komentar, bahkan dengan memori semacam itu, jika Anda memiliki beberapa juta item dari satu jenis - seperti array - maka ukuran variabel dapat membuat perbedaan.
Jika Anda masuk ke dunia sistem embedded - yang tidak benar-benar di luar lingkup pertanyaan, karena OP tidak membatasinya untuk PC - maka ukuran tipe data sangat penting. Saya baru saja menyelesaikan proyek cepat pada mikrokontroler 8-bit yang hanya memiliki 8K kata memori program dan 368 byte RAM. Di sana, jelas setiap byte dihitung. Seseorang tidak pernah menggunakan variabel yang lebih besar dari yang mereka butuhkan (baik dari sudut pandang ruang, dan ukuran kode - prosesor 8-bit menggunakan banyak instruksi untuk memanipulasi data 16 dan 32-bit). Mengapa menggunakan CPU dengan sumber daya yang terbatas? Dalam jumlah besar, harganya hanya seperempat.
Saat ini saya sedang melakukan proyek tertanam lainnya dengan mikrokontroler berbasis MIPS 32-bit yang memiliki flash 512K byte dan 128K byte RAM (dan biaya sekitar $ 6 dalam jumlah). Seperti halnya PC, ukuran data "alami" adalah 32-bit. Sekarang menjadi lebih efisien, kode-bijaksana, untuk menggunakan int untuk sebagian besar variabel, bukan karakter atau celana pendek. Tetapi sekali lagi, segala jenis array atau struktur harus dipertimbangkan apakah diperlukan tipe data yang lebih kecil. Tidak seperti kompiler untuk sistem yang lebih besar, kemungkinan besar variabel dalam struktur akan dikemas pada sistem tertanam. Saya berhati-hati untuk selalu mencoba untuk menempatkan semua variabel 32-bit terlebih dahulu, lalu 16-bit, lalu 8-bit untuk menghindari "lubang".
sumber
Jawabannya tergantung pada sistem Anda. Secara umum, berikut ini kelebihan dan kekurangan menggunakan jenis yang lebih kecil:
Keuntungan
Kekurangan
Saran saya adalah menyukai ini:
Atau, Anda dapat menggunakan
int_leastn_t
atauint_fastn_t
dari stdint.h, di mana n adalah angka 8, 16, 32 atau 64.int_leastn_t
tipe berarti "Saya ingin ini setidaknya n byte tetapi saya tidak peduli jika kompiler mengalokasikannya sebagai tipe yang lebih besar sesuai dengan perataan ".int_fastn_t
berarti "Saya ingin ini menjadi n byte panjang, tetapi jika itu akan membuat kode saya akan berjalan lebih cepat, kompiler harus menggunakan tipe yang lebih besar daripada yang ditentukan".Secara umum, berbagai tipe stdint.h adalah praktik yang jauh lebih baik daripada yang
int
lain-lain, karena mereka portabel. Tujuannyaint
adalah untuk tidak memberikan lebar yang ditentukan hanya untuk membuatnya portabel. Tetapi pada kenyataannya, sulit untuk port karena Anda tidak pernah tahu seberapa besar itu pada sistem tertentu.sumber
Bergantung pada cara kerja sistem operasi tertentu, Anda biasanya mengharapkan memori untuk dialokasikan tidak dioptimalkan sehingga ketika Anda memanggil byte, atau kata atau beberapa tipe data kecil yang akan dialokasikan, nilai menempati seluruh register semua itu sangat sendiri. Bagaimana kompiler atau penerjemah Anda bekerja untuk mengartikan ini adalah sesuatu yang lain, jadi jika Anda mengkompilasi program dalam C # misalnya, nilai secara fisik mungkin menempati register untuk dirinya sendiri, namun nilainya akan diperiksa batas untuk memastikan Anda tidak cobalah untuk menyimpan nilai yang akan melampaui batas dari tipe data yang dimaksudkan.
Kinerja-bijaksana, dan jika Anda benar-benar jago tentang hal-hal seperti itu, kemungkinan lebih cepat untuk hanya menggunakan tipe data yang paling cocok dengan ukuran register target, tetapi kemudian Anda kehilangan semua gula sintaksis indah yang membuat bekerja dengan variabel sangat mudah .
Bagaimana ini membantu Anda? Nah, itu benar-benar terserah Anda untuk memutuskan situasi seperti apa yang Anda koding. Untuk hampir setiap program yang pernah saya tulis, cukup percaya pada kompiler Anda untuk mengoptimalkan berbagai hal dan menggunakan tipe data yang paling berguna bagi Anda. Jika Anda membutuhkan presisi tinggi, gunakan tipe data floating point yang lebih besar. Jika bekerja dengan hanya nilai positif, Anda mungkin dapat menggunakan integer yang tidak ditandatangani, tetapi sebagian besar, cukup menggunakan int datatype sudah cukup.
Namun, jika Anda memiliki beberapa persyaratan data yang sangat ketat, seperti menulis protokol komunikasi, atau semacam algoritma enkripsi, maka menggunakan tipe data rentang-periksa bisa sangat berguna, terutama jika Anda mencoba menghindari masalah yang berkaitan dengan overruns / underruns data. , atau nilai data tidak valid.
Satu-satunya alasan lain yang dapat saya pikirkan dari atas kepala saya untuk menggunakan tipe data tertentu adalah ketika Anda mencoba untuk mengomunikasikan maksud dalam kode Anda. Jika Anda menggunakan shortint misalnya, Anda memberi tahu pengembang lain bahwa Anda mengizinkan angka positif dan negatif dalam rentang nilai yang sangat kecil.
sumber
Seperti yang dikomentari scarfridge , ini adalah a
Mencoba mengoptimalkan penggunaan memori dapat memengaruhi area kinerja lainnya, dan aturan utama pengoptimalan adalah:
Untuk mengetahui apakah sekarang saatnya mengoptimalkan, perlu dilakukan benchmarking dan pengujian. Anda perlu tahu di mana kode Anda tidak efisien, sehingga Anda dapat menargetkan optimasi Anda.
Dalam rangka untuk menentukan apakah dioptimalkan versi kode ini sebenarnya lebih baik dari pelaksanaan naif pada waktu tertentu, Anda perlu patokan mereka sisi-by-side dengan data yang sama.
Juga, ingat bahwa hanya karena implementasi yang diberikan lebih efisien pada generasi CPU saat ini, tidak berarti akan selalu begitu. Jawaban saya atas pertanyaan Apakah optimasi mikro penting saat pengkodean? merinci contoh dari pengalaman pribadi di mana optimasi usang menghasilkan urutan besarnya perlambatan.
Pada banyak prosesor, akses memori yang tidak selaras jauh lebih mahal daripada akses memori yang selaras. Mengemas beberapa celana pendek ke struct Anda mungkin hanya berarti bahwa program Anda harus melakukan operasi pack / unpack setiap kali Anda menyentuh salah satu nilai.
Karena alasan ini, kompiler modern mengabaikan saran Anda. Seperti komentar nikie :
Tebak kompiler Anda dengan risiko sendiri.
Ada tempat untuk optimisasi seperti itu, ketika bekerja dengan dataset terabyte atau pengendali mikro tertanam, tetapi bagi kebanyakan dari kita, itu tidak benar-benar menjadi perhatian.
sumber
Ini salah. Anda tidak dapat membuat asumsi tentang berapa banyak byte masing-masing jenis memegang, selain
char
menjadi satu byte dan setidaknya 8 bit per byte, bersama dengan ukuran masing-masing jenis menjadi lebih besar atau sama dengan sebelumnya.Manfaat kinerja sangat kecil untuk variabel stack - mereka mungkin akan tetap selaras / padded.
Karena ini,
short
danlong
praktis tidak digunakan saat ini, dan Anda hampir selalu lebih baik menggunakanint
.Tentu saja, ada juga
stdint.h
yang bisa digunakan saatint
tidak memotongnya. Jika Anda pernah mengalokasikan array besar integer / struct makaintX_t
masuk akal karena Anda bisa efisien dan bergantung pada ukuran tipe. Ini sama sekali tidak prematur karena Anda dapat menghemat megabita memori.sumber
long
mungkin berbeda denganint
. Jika kompiler Anda adalah LP64,int
adalah 32 bit danlong
64 bit dan Anda akan menemukan bahwaint
s mungkin masih sejajar dengan 4 byte (misalnya kompiler saya).int64_t
int32_t
,,int_fast32_t
danlong
semuanya merupakan pilihan yang baik,long long
hanya boros, danint
tidak portabel.Ini akan dari sudut pandang OOP dan / atau perusahaan / aplikasi dan mungkin tidak berlaku di bidang / domain tertentu, tapi saya agak ingin memunculkan konsep obsesi primitif .
Merupakan ide yang bagus untuk menggunakan tipe data yang berbeda untuk berbagai jenis informasi dalam aplikasi Anda. Namun, mungkin bukan ide yang baik untuk menggunakan tipe bawaan untuk ini, kecuali jika Anda memiliki beberapa masalah kinerja yang serius (yang telah diukur dan diverifikasi dan sebagainya).
Jika kita ingin memodelkan suhu di Kelvin dalam aplikasi kita, kita BISA menggunakan
ushort
atauuint
atau sesuatu yang serupa dengan menyatakan bahwa "gagasan tentang derajat negatif Kelvin tidak masuk akal dan kesalahan logika domain". Gagasan di balik ini masuk akal, tetapi Anda tidak akan sepenuhnya. Apa yang kami sadari adalah bahwa kami tidak dapat memiliki nilai negatif, jadi sangat berguna jika kami bisa mendapatkan kompiler untuk memastikan tidak ada yang memberikan nilai negatif ke suhu Kelvin. JUGA benar bahwa Anda tidak dapat melakukan operasi bitwise pada suhu. Dan Anda tidak bisa menambahkan ukuran berat (kg) ke suhu (K). Tetapi jika Anda memodelkan suhu dan massa sebagaiuint
s, kita dapat melakukan hal itu.Menggunakan tipe bawaan untuk memodelkan entitas DOMAIN kami akan mengarah pada beberapa kode berantakan dan beberapa cek yang terlewat dan invarian yang rusak. Bahkan jika suatu tipe menangkap BEBERAPA bagian dari entitas (tidak boleh negatif), itu pasti akan kehilangan yang lain (tidak dapat digunakan dalam ekspresi aritmatika yang sewenang-wenang, tidak dapat diperlakukan sebagai array bit, dll.)
Solusinya adalah mendefinisikan tipe baru yang merangkum invarian. Dengan cara ini Anda dapat memastikan bahwa uang adalah uang dan jarak adalah jarak, dan Anda tidak dapat menambahkannya bersama-sama, dan Anda tidak dapat membuat jarak negatif, tetapi Anda BISA membuat jumlah uang yang negatif (atau hutang). Tentu saja, tipe ini akan menggunakan tipe bawaan secara internal, tetapi ini disembunyikan dari klien. Berkaitan dengan pertanyaan Anda tentang konsumsi kinerja / memori, hal semacam ini dapat memungkinkan Anda untuk mengubah bagaimana hal-hal disimpan secara internal tanpa mengubah antarmuka fungsi Anda yang beroperasi pada entitas domain Anda, jika Anda mengetahui itu, a
short
terlalu berlebihan besar.sumber
Ya tentu saja. Sebaiknya gunakan
uint_least8_t
kamus, susunan konstanta besar, buffer dll. Lebih baik digunakanuint_fast8_t
untuk keperluan pemrosesan.uint8_least_t
(penyimpanan) ->uint8_fast_t
(pemrosesan) ->uint8_least_t
(penyimpanan).Misalnya Anda mengambil simbol 8 bit dari
source
, kode 16 bit daridictionaries
dan beberapa 32 bitconstants
. Daripada Anda memproses operasi 10-15 bit dengan mereka dan output 8 bitdestination
.Bayangkan Anda harus memproses 2 gigabita
source
. Jumlah operasi bit sangat besar. Anda akan menerima bonus kinerja yang luar biasa jika Anda akan beralih ke tipe cepat selama pemrosesan. Tipe cepat dapat berbeda untuk setiap keluarga CPU. Anda dapat menyertakanstdint.h
dan penggunaanuint_fast8_t
,uint_fast16_t
,uint_fast32_t
, dllAnda bisa menggunakannya
uint_least8_t
sebagai gantiuint8_t
portabilitas. Tapi tidak ada yang tahu cpu modern apa yang akan menggunakan fitur ini. Mesin VAC adalah benda museum. Jadi mungkin itu adalah pembunuhan yang berlebihan.sumber