sizeof style: sizeof (jenis) atau sizeof variabel?

22

Saya telah melihat dua gaya penggunaan sizeofuntuk operasi yang berhubungan dengan memori (seperti dalam memsetatau malloc):

  • sizeof(type), dan
  • sizeof variable atau sizeof(variable)

Yang mana yang Anda inginkan, atau Anda akan menggunakan campuran dari dua gaya, dan kapan Anda akan menggunakan masing-masing gaya? Apa pro dan kontra dari masing-masing gaya dan kapan Anda menggunakannya?

Sebagai contoh, saya dapat melihat pasangan situasi berikut di mana satu gaya membantu dan yang lainnya tidak:

Ketika Anda mendapatkan pointer tipuan salah:

type *var;
...
memset(var, 0, sizeof var);    /* oops */

Ketika jenisnya berubah:

new_type var;    /* changed from old_type to new_type */
...
memset(&var, 0, sizeof(old_type));    /* oops */
congusbongus
sumber

Jawaban:

30

Saya perfer sizeof(variable)lebih sizeof(type). Mempertimbangkan:

int a1;
float a2;
memset(&a1,0,sizeof(a1));
memset(&a2,0,sizeof(a2));

vs.

int a1;
float a2;
memset(&a1,0,sizeof(int));
memset(&a2,0,sizeof(float));

Dalam kasus pertama, mudah untuk memverifikasi bahwa ukuran yang tepat sedang diteruskan memset. Dalam kasus kedua, Anda harus terus-menerus meninjau bagian atas dan bawah untuk memastikan Anda konsisten.

ay32
sumber
4
Juga, jika Anda mengubah tipe variabel, kode yang mengasumsikan tipe tersebut harus berubah. Saya pikir lebih baik kode yang benar dengan sedikit ketergantungan pada jenisnya. (Saya dipengaruhi oleh proyek konversi besar 16 bit ke 32 bit pada hari itu.)
Gort the Robot
Ini adalah lebih untuk bekerja dengan array C di mana tidak umum untuk membuat typedef, tapi penggunaan hal-hal seperti char array [MAX_SIZE];
mattnz
@ vy32: Salah 1: "sizeof (array) TIDAK mengembalikan ukuran array ... ukuran pointer ke array" - jika arraymemang array C, maka sizeof(array)mengembalikan jumlah byte yang diperlukan untuk menyimpan elemen array . Jika arrayadalah pointer ke elemen pertama dari array C yang rusak, maka pernyataan Anda berlaku. Melewati C array sebagai argumen fungsi membuatnya tampak seperti pointer dalam fungsi - semua informasi membuktikan itu sebuah array, seperti ukurannya, hilang. Itu sebabnya busuk . Salah 2: "array tidak benar-benar ada di C; ... hanya sintaksis gula untuk pointer."
Johann Gerell
9

Preferensi (seperti biasa) adalah untuk mencerminkan niat Anda secara langsung.

Apakah niat untuk beroperasi melawan memori variabel yang ada? Jika demikian, maka gunakan sizeof(variable), sebagai acara ini sedekat mungkin bahwa itu variabel memori itu sendiri bahwa Anda peduli.

Adalah niat untuk melakukan beberapa perhitungan pada jenis, misalnya untuk menentukan berapa banyak memori yang harus dialokasikan untuk contoh baru? Jika demikian, maka gunakan sizeof(type).

Yaitu, saya lebih suka

struct foo *bar;
bar = (struct foo *) malloc(sizeof(struct foo));

lebih

bar = (struct foo *) malloc(sizeof(*bar));

karena case terakhir sepertinya Anda sedang mencoba mengakses variabel yang belum ada.

Di sisi lain, saya lebih suka

char Buffer[256];
memset(Buffer, 0, sizeof(Buffer));

lebih

char Buffer[256];
memset(Buffer, 0, 256 * sizeof(char));

sebagai niat jelas untuk nol-mengisi isi dari variabel, sehingga variabel kita harus beroperasi melawan. Mencoba menggunakan tipe metadata hanya membingungkan hal-hal di sini.

Aidan Cully
sumber
Saya selalu melakukan, tapi itu masalah selera pribadi. Saya menganggap bahwa void *itu secara otomatis dilemparkan ke jenis pointer lain sebagai kesalahan.
Aidan Cully
3

Saya akan jauh lebih suka sizeof(type)lebih sizeof variable. Meskipun memaksa Anda untuk khawatir tentang jenis dan membuat perubahan yang lebih, hal ini membantu Anda menghindari kesalahan pointer tipuan, yang peringkat di antara penyebab paling umum dari bug di C .

Saya tidak akan terlalu khawatir tentang bug di mana jenisnya sizeof(type)berubah; setiap kali Anda mengubah jenis variabel, Anda harus melakukan pemindaian cepat untuk melihat di mana variabel itu digunakan dan jika Anda perlu mengubah sizeof(type)pernyataan apa pun . Meskipun selalu ada kemungkinan untuk mendapatkan ini salah, ia memiliki risiko yang jauh lebih rendah daripada kesalahan tipuan pointer.

Salah satu keuntungannya sizeof variableadalah untuk array, tetapi dalam praktiknya saya telah menemukan bahwa melewati array sebagai pasangan pertama / len jauh lebih umum (dalam hal ini hanya menggunakan panjangnya), plus itu juga sangat mudah untuk mendapatkan ukuran yang salah karena peluruhan array / pointer, seperti dalam contoh ini:

ID_INLINE mat3_t::mat3_t( float src[ 3 ][ 3 ] ) {
  memcpy( mat, src, sizeof( src ) );    /* NOT the same as 3*3*sizeof(float) */
}
congusbongus
sumber
2
"Pemindaian cepat untuk melihat di mana variabel itu digunakan .... selalu ada kesempatan untuk mendapatkan kesalahan ini" - bagi saya ini adalah bahaya terbesar melakukan sizeof (tipe), itulah sebabnya saya selalu melakukan sizeof (variabel). Karena hasil akhir dari bahaya ini adalah bahwa semuanya mungkin masih dikompilasi dan bahkan jika Anda membuat satu kesalahan, mungkin Anda butuh lebih dari satu tahun atau crash dan buffer korupsi acak sebelum Anda menangkapnya. Dan saya tidak dapat membuat koneksi (jelas jendela waktu saya per pertanyaan adalah sekitar 30 detik) antara pertanyaan ini dan "kesalahan penunjuk arah".
DXM
@ DXM Dengan ukuran operan, jika nilainya maka itu sizeof var; jika itu adalah pointer itu sizeof *var. Ini juga sesuatu yang orang bisa salah, dan kompiler akan dengan senang hati mengambilnya tanpa keluhan. Saya berpendapat bahwa kesalahan-kesalahan ini jauh lebih sulit dikenali, dan lebih umum, daripada kesalahan dalam sizeof(type)bentuk.
congusbongus
1
Jenis dan ukuran operator C Anda berdua benar-benar rusak secara fundamental dan tidak akan pernah dapat diandalkan, tidak ada yang dapat Anda perbaiki karena programmer dapat memperbaikinya.
mattnz
Ketika posting ditandai C, memposting kode C lebih informatif daripada kode C ++ mat3_t::mat3_t(...).
chux - Reinstate Monica
0

Tujuannya adalah untuk menghapus redundansi. Jika Anda menggunakan sizeof untuk operasi yang terkait dengan variabel, maka jelas Anda harus mencerminkannya dalam sizeof. Ya, Anda dapat mengacaukan seperti pada contoh pertama, tetapi obatnya tidak menggunakan tipe, tetapi * var, dengan benar sesuai dengan tujuannya.

Untuk mengurangi masalah seperti itu, biasanya menggunakan makro, templat, dan alat serupa yang dilatih untuk use case alih-alih ukuran telanjang.

Lihat makro CLEAR saya yang digunakan secara eksklusif, bukan memset telanjang. Menyelamatkan pantat saya beberapa kali dalam kasus kesalahan tipuan atau ketika konten struct mengambil vektor atau string ...

Balog Pal
sumber
Makro seperti itulah yang memberi nama buruk pemrograman Makro kepada C
mattnz
@ mattnz: tolong tunjukkan alternatif yang lebih baik. Jauh lebih mudah untuk berbicara hal-hal abstrak daripada membuat program yang benar-benar berfungsi
Balog Pal
1
Makro tertaut adalah C ++, dan posting ini diberi tag 'C' (Mereka adalah bahasa yang berbeda), Ada akan menjadi saran saya.
mattnz
@ mattnz: dan topik yang sama menunjukkan bagaimana menegakkan dengan cara yang sama untuk C. Anda tampaknya benar-benar kehilangan intinya, itu bukan implementasi konten yang sebenarnya tetapi penggunaan yang lebih aman dibandingkan dengan hal-hal mentah. Btw juga bisa dibaca.
Balog Pal
0

Logika bisnis menentukan pilihan Anda.

  1. Jika kode Anda merujuk ke variabel tertentu dan tanpa variabel ini kode Anda tidak masuk akal - pilih sizeof(var)

  2. Jika kode Anda berkaitan dengan serangkaian variabel dengan tipe tertentu - pilih sizeof(type). Biasanya Anda memerlukan ini jika Anda memiliki typedefyang mendefinisikan banyak variabel yang Anda proses berbeda berdasarkan jenisnya (misalnya serialisasi). Anda mungkin tidak tahu mana dari variabel-variabel ini yang akan tetap dalam versi kode masa depan sehingga memilih jenis sebagai argumen secara logis benar. Bahkan mengubah seperti typedefitu tidak akan mempengaruhi garis sizeof Anda.

Riga
sumber
-1

Tergantung pada tujuan sizeof (variabel) bisa menjadi solusi terbaik. Dengan cara itu, Anda dapat mengubah jenis variabel Anda jika perlu, tanpa memperbaiki semua entri untuk jenis itu. Tetapi sekali lagi, itu tergantung pada tujuan Anda.

Pedro Perez
sumber